From 1ad432fd9c90fe4d953815d3c6be63bc31c51598 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Mon, 2 Mar 2020 02:52:41 +0400 Subject: [PATCH] Update tonlib --- Wallet/Info.plist | 4 + .../Wallet.tulsiproj/Configs/Default.tulsigen | 61 - Wallet/Wallet.tulsiproj/peter.tulsiconf-user | 10 - Wallet/Wallet.tulsiproj/project.tulsiconf | 14 - submodules/TonBinding/Sources/TON.h | 38 +- submodules/TonBinding/Sources/TON.mm | 178 +- .../WalletCore/Sources/WalletCore.swift | 65 +- .../Sources/WalletInfoTransactionItem.swift | 18 +- .../Sources/WalletTransactionInfoScreen.swift | 18 +- submodules/ton/BUILD | 14 +- submodules/ton/tonlib-src.tar.gz | Bin 1490956 -> 0 bytes submodules/ton/tonlib-src/LGPLv2 | 2 +- submodules/ton/tonlib-src/README | 9 +- .../ton/tonlib-src/adnl/adnl-node-id.hpp | 6 +- .../ton/tonlib-src/common/int-to-string.hpp | 18 + .../ton/tonlib-src/crypto/CMakeLists.txt | 28 +- .../tonlib-src/crypto/block/adjust-block.cpp | 203 + .../tonlib-src/crypto/block/block-auto.cpp | 4851 +++++++++++++++-- .../ton/tonlib-src/crypto/block/block-auto.h | 1650 +++++- .../tonlib-src/crypto/block/block-parse.cpp | 573 +- .../ton/tonlib-src/crypto/block/block-parse.h | 145 +- .../ton/tonlib-src/crypto/block/block.cpp | 46 +- .../ton/tonlib-src/crypto/block/block.h | 19 +- .../ton/tonlib-src/crypto/block/block.tlb | 79 + .../tonlib-src/crypto/block/check-proof.cpp | 15 +- .../ton/tonlib-src/crypto/block/check-proof.h | 7 +- .../tonlib-src/crypto/block/create-state.cpp | 85 +- .../tonlib-src/crypto/block/dump-block.cpp | 63 +- .../ton/tonlib-src/crypto/block/mc-config.cpp | 53 +- .../ton/tonlib-src/crypto/block/mc-config.h | 7 +- .../tonlib-src/crypto/block/transaction.cpp | 151 +- .../ton/tonlib-src/crypto/block/transaction.h | 18 +- .../ton/tonlib-src/crypto/common/bigint.hpp | 13 +- .../ton/tonlib-src/crypto/common/refint.cpp | 52 +- .../ton/tonlib-src/crypto/common/refint.h | 16 +- .../ton/tonlib-src/crypto/common/util.cpp | 66 +- .../ton/tonlib-src/crypto/common/util.h | 14 +- .../ton/tonlib-src/crypto/fift/IntCtx.cpp | 5 + .../ton/tonlib-src/crypto/fift/IntCtx.h | 5 + .../ton/tonlib-src/crypto/fift/fift-main.cpp | 4 +- .../ton/tonlib-src/crypto/fift/lib/Asm.fif | 129 +- .../ton/tonlib-src/crypto/fift/lib/Color.fif | 21 + .../ton/tonlib-src/crypto/fift/lib/Fift.fif | 20 + .../ton/tonlib-src/crypto/fift/lib/GetOpt.fif | 131 + .../tonlib-src/crypto/fift/lib/TonUtil.fif | 52 +- .../ton/tonlib-src/crypto/fift/utils.cpp | 7 + .../ton/tonlib-src/crypto/fift/words.cpp | 490 +- submodules/ton/tonlib-src/crypto/fift/words.h | 4 +- .../ton/tonlib-src/crypto/func/abscode.cpp | 26 +- .../ton/tonlib-src/crypto/func/analyzer.cpp | 43 +- .../ton/tonlib-src/crypto/func/asmops.cpp | 41 +- .../ton/tonlib-src/crypto/func/builtins.cpp | 63 +- .../ton/tonlib-src/crypto/func/codegen.cpp | 160 +- .../ton/tonlib-src/crypto/func/func.cpp | 5 + submodules/ton/tonlib-src/crypto/func/func.h | 153 +- .../tonlib-src/crypto/func/gen-abscode.cpp | 74 +- .../ton/tonlib-src/crypto/func/keywords.cpp | 6 +- .../ton/tonlib-src/crypto/func/optimize.cpp | 207 +- .../ton/tonlib-src/crypto/func/parse-func.cpp | 179 +- .../crypto/func/stack-transform.cpp | 240 +- .../ton/tonlib-src/crypto/func/test/a10.fc | 9 + .../ton/tonlib-src/crypto/func/test/a11.fc | 28 + .../ton/tonlib-src/crypto/func/test/a6_4.fc | 20 + .../ton/tonlib-src/crypto/func/test/a6_5.fc | 20 + .../ton/tonlib-src/crypto/func/test/c1.fc | 37 + .../ton/tonlib-src/crypto/func/test/c2.fc | 10 + .../ton/tonlib-src/crypto/func/test/c2_1.fc | 7 + .../ton/tonlib-src/crypto/func/test/w8.fc | 22 + .../ton/tonlib-src/crypto/func/test/w9.fc | 8 + .../tonlib-src/crypto/func/unify-types.cpp | 42 +- .../ton/tonlib-src/crypto/parser/symtable.h | 2 +- .../crypto/smartcont/CreateState.fif | 4 + .../tonlib-src/crypto/smartcont/auto-dns.fif | 115 + .../crypto/smartcont/auto/config-code.cpp | 2 +- .../crypto/smartcont/auto/config-code.fif | 295 +- .../crypto/smartcont/auto/dns-auto-code.cpp | 1 + .../crypto/smartcont/auto/dns-auto-code.fif | 949 ++++ .../crypto/smartcont/auto/dns-manual-code.cpp | 1 + .../crypto/smartcont/auto/dns-manual-code.fif | 477 ++ .../crypto/smartcont/auto/elector-code.cpp | 2 +- .../crypto/smartcont/auto/elector-code.fif | 680 +-- .../smartcont/auto/highload-wallet-code.cpp | 2 +- .../smartcont/auto/highload-wallet-code.fif | 12 +- .../auto/highload-wallet-v2-code.cpp | 2 +- .../auto/highload-wallet-v2-code.fif | 28 +- .../crypto/smartcont/auto/multisig-code.cpp | 2 +- .../crypto/smartcont/auto/multisig-code.fif | 605 +- .../smartcont/auto/restricted-wallet-code.cpp | 2 +- .../smartcont/auto/restricted-wallet-code.fif | 15 +- .../auto/restricted-wallet2-code.cpp | 2 +- .../auto/restricted-wallet2-code.fif | 15 +- .../smartcont/auto/simple-wallet-code.cpp | 2 +- .../smartcont/auto/simple-wallet-ext-code.cpp | 2 +- .../smartcont/auto/simple-wallet-ext-code.fif | 10 +- .../crypto/smartcont/auto/wallet-code.cpp | 2 +- .../crypto/smartcont/auto/wallet-code.fif | 9 + .../crypto/smartcont/auto/wallet3-code.cpp | 2 +- .../crypto/smartcont/auto/wallet3-code.fif | 9 + .../crypto/smartcont/config-code.fc | 78 +- .../crypto/smartcont/dns-auto-code.fc | 514 ++ .../crypto/smartcont/dns-manual-code.fc | 348 ++ .../crypto/smartcont/elector-code.fc | 34 +- .../crypto/smartcont/gen-zerostate.fif | 43 +- .../crypto/smartcont/highload-wallet-code.fc | 6 + .../smartcont/highload-wallet-v2-code.fc | 6 + .../crypto/smartcont/highload-wallet-v2.fif | 41 +- .../crypto/smartcont/highload-wallet.fif | 41 +- .../crypto/smartcont/manual-dns-manage.fif | 146 + .../crypto/smartcont/multisig-code.fc | 109 +- .../crypto/smartcont/new-auto-dns.fif | 66 + .../crypto/smartcont/new-manual-dns.fif | 63 + .../crypto/smartcont/new-wallet-v2.fif | 4 +- .../crypto/smartcont/new-wallet-v3.fif | 9 +- .../crypto/smartcont/new-wallet.fif | 4 +- .../smartcont/restricted-wallet-code.fc | 10 +- .../smartcont/restricted-wallet2-code.fc | 8 +- .../tonlib-src/crypto/smartcont/show-addr.fif | 13 +- .../crypto/smartcont/simple-wallet-code.fc | 2 +- .../smartcont/simple-wallet-ext-code.fc | 11 +- .../ton/tonlib-src/crypto/smartcont/stdlib.fc | 115 +- .../crypto/smartcont/update-config-smc.fif | 11 +- .../crypto/smartcont/validator-elect-req.fif | 2 +- .../smartcont/validator-elect-signed.fif | 2 +- .../crypto/smartcont/wallet-code.fc | 6 + .../tonlib-src/crypto/smartcont/wallet-v2.fif | 52 +- .../tonlib-src/crypto/smartcont/wallet-v3.fif | 51 +- .../tonlib-src/crypto/smartcont/wallet.fif | 52 +- .../crypto/smartcont/wallet3-code.fc | 6 + .../crypto/smc-envelope/HighloadWallet.cpp | 142 + .../crypto/smc-envelope/HighloadWallet.h | 63 + .../crypto/smc-envelope/HighloadWalletV2.cpp | 151 + .../crypto/smc-envelope/HighloadWalletV2.h | 66 + .../crypto/smc-envelope/ManualDns.cpp | 604 ++ .../crypto/smc-envelope/ManualDns.h | 335 ++ .../crypto/smc-envelope/MultisigWallet.cpp | 47 +- .../crypto/smc-envelope/MultisigWallet.h | 25 +- .../crypto/smc-envelope/SmartContract.cpp | 36 +- .../crypto/smc-envelope/SmartContract.h | 12 +- .../crypto/smc-envelope/SmartContractCode.cpp | 170 +- .../crypto/smc-envelope/SmartContractCode.h | 13 +- .../crypto/smc-envelope/TestGiver.cpp | 25 +- .../crypto/smc-envelope/TestGiver.h | 21 +- .../crypto/smc-envelope/TestWallet.cpp | 76 +- .../crypto/smc-envelope/TestWallet.h | 32 +- .../tonlib-src/crypto/smc-envelope/Wallet.cpp | 78 +- .../tonlib-src/crypto/smc-envelope/Wallet.h | 30 +- .../crypto/smc-envelope/WalletInterface.h | 72 + .../crypto/smc-envelope/WalletV3.cpp | 115 +- .../tonlib-src/crypto/smc-envelope/WalletV3.h | 40 +- .../tonlib-src/crypto/test/fift/testdict.fif | 12 +- .../tonlib-src/crypto/test/fift/testdict2.fif | 52 + .../ton/tonlib-src/crypto/test/test-db.cpp | 317 +- .../tonlib-src/crypto/test/test-smartcont.cpp | 706 ++- submodules/ton/tonlib-src/crypto/test/vm.cpp | 4 +- .../ton/tonlib-src/crypto/tl/tlbc-gen-cpp.cpp | 65 +- submodules/ton/tonlib-src/crypto/tl/tlbc.cpp | 9 +- .../ton/tonlib-src/crypto/tl/tlblib.cpp | 64 +- .../ton/tonlib-src/crypto/tl/tlblib.hpp | 263 +- .../ton/tonlib-src/crypto/vm/arithops.cpp | 24 +- .../ton/tonlib-src/crypto/vm/cellops.cpp | 27 +- .../crypto/vm/cells/CellBuilder.cpp | 54 +- .../tonlib-src/crypto/vm/cells/CellBuilder.h | 7 +- .../tonlib-src/crypto/vm/cells/CellSlice.cpp | 58 +- .../tonlib-src/crypto/vm/cells/CellSlice.h | 10 +- .../tonlib-src/crypto/vm/cells/CellString.cpp | 93 + .../tonlib-src/crypto/vm/cells/CellString.h | 43 + .../crypto/vm/cells/MerkleProof.cpp | 97 +- .../tonlib-src/crypto/vm/cells/MerkleProof.h | 3 + .../crypto/vm/cells/MerkleUpdate.cpp | 2 +- .../ton/tonlib-src/crypto/vm/continuation.cpp | 852 +-- .../ton/tonlib-src/crypto/vm/continuation.h | 352 +- .../ton/tonlib-src/crypto/vm/contops.cpp | 17 +- submodules/ton/tonlib-src/crypto/vm/cp0.cpp | 5 +- submodules/ton/tonlib-src/crypto/vm/cp0.h | 4 +- .../ton/tonlib-src/crypto/vm/debugops.cpp | 23 +- .../ton/tonlib-src/crypto/vm/debugops.h | 3 +- submodules/ton/tonlib-src/crypto/vm/dict.cpp | 307 +- submodules/ton/tonlib-src/crypto/vm/dict.h | 181 +- .../ton/tonlib-src/crypto/vm/dictops.cpp | 41 +- submodules/ton/tonlib-src/crypto/vm/log.h | 8 +- submodules/ton/tonlib-src/crypto/vm/memo.cpp | 33 + submodules/ton/tonlib-src/crypto/vm/memo.h | 37 + .../ton/tonlib-src/crypto/vm/opctable.cpp | 4 +- submodules/ton/tonlib-src/crypto/vm/stack.cpp | 351 +- submodules/ton/tonlib-src/crypto/vm/stack.hpp | 103 +- .../ton/tonlib-src/crypto/vm/stackops.cpp | 16 +- .../ton/tonlib-src/crypto/vm/tonops.cpp | 277 +- .../ton/tonlib-src/crypto/vm/tupleops.cpp | 25 +- submodules/ton/tonlib-src/crypto/vm/utils.cpp | 152 + submodules/ton/tonlib-src/crypto/vm/utils.h | 29 + submodules/ton/tonlib-src/crypto/vm/vm.cpp | 618 +++ submodules/ton/tonlib-src/crypto/vm/vm.h | 320 ++ submodules/ton/tonlib-src/crypto/vm/vmstate.h | 10 +- .../lite-client/lite-client-common.cpp | 21 + .../lite-client/lite-client-common.h | 19 + .../tonlib-src/lite-client/lite-client.cpp | 935 +++- .../ton/tonlib-src/lite-client/lite-client.h | 68 +- .../tdactor/benchmark/benchmark.cpp | 351 +- .../benchmark/third_party/MoodyCamelQueue.h | 136 +- .../tdactor/td/actor/core/ActorInfo.h | 3 +- .../tdactor/td/actor/core/CpuWorker.cpp | 56 +- .../tdactor/td/actor/core/CpuWorker.h | 19 +- .../tdactor/td/actor/core/Scheduler.cpp | 57 +- .../tdactor/td/actor/core/Scheduler.h | 54 +- .../tdactor/td/actor/core/SchedulerId.h | 27 +- .../tonlib-src/tdactor/test/actors_core.cpp | 16 +- .../tonlib-src/tddb/td/db/MemoryKeyValue.h | 6 +- .../ton/tonlib-src/tddb/td/db/RocksDb.cpp | 12 + .../ton/tonlib-src/tddb/td/db/RocksDb.h | 4 + .../ton/tonlib-src/tddb/test/binlog.cpp | 2 +- .../ton/tonlib-src/tddb/test/key_value.cpp | 22 +- .../ton/tonlib-src/tdutils/CMakeLists.txt | 4 + .../tonlib-src/tdutils/td/utils/BufferedFd.h | 8 +- .../tonlib-src/tdutils/td/utils/FileLog.cpp | 8 +- .../ton/tonlib-src/tdutils/td/utils/FileLog.h | 4 +- .../tonlib-src/tdutils/td/utils/MpmcQueue.h | 20 +- .../tonlib-src/tdutils/td/utils/MpmcWaiter.h | 269 +- .../tdutils/td/utils/SharedObjectPool.h | 9 +- .../ton/tonlib-src/tdutils/td/utils/Span.h | 8 +- .../ton/tonlib-src/tdutils/td/utils/Status.h | 5 +- .../tdutils/td/utils/StealingQueue.h | 124 + .../tdutils/td/utils/StringBuilder.h | 2 +- .../tonlib-src/tdutils/td/utils/TsFileLog.cpp | 14 +- .../tonlib-src/tdutils/td/utils/TsFileLog.h | 7 +- .../ton/tonlib-src/tdutils/td/utils/Variant.h | 6 +- .../tonlib-src/tdutils/td/utils/base64.cpp | 64 +- .../ton/tonlib-src/tdutils/td/utils/base64.h | 5 +- .../ton/tonlib-src/tdutils/td/utils/bits.h | 8 +- .../ton/tonlib-src/tdutils/td/utils/misc.h | 22 +- .../tonlib-src/tdutils/td/utils/optional.h | 9 +- .../tdutils/td/utils/port/detail/Epoll.cpp | 3 +- .../tdutils/td/utils/port/rlimit.cpp | 102 + .../tonlib-src/tdutils/td/utils/port/rlimit.h | 32 + .../tonlib-src/tdutils/td/utils/port/user.cpp | 18 + .../tonlib-src/tdutils/td/utils/port/user.h | 18 + .../tonlib-src/tdutils/test/MpmcWaiter.cpp | 48 +- .../tonlib-src/tdutils/test/StealingQueue.cpp | 153 + .../ton/tonlib-src/tdutils/test/log.cpp | 5 +- .../ton/tonlib-src/tdutils/test/misc.cpp | 27 +- .../ton/tonlib-src/terminal/terminal.cpp | 105 +- submodules/ton/tonlib-src/terminal/terminal.h | 20 +- .../ton/tonlib-src/terminal/terminal.hpp | 6 +- .../ton/tonlib-src/test/regression-tests.ans | 8 +- .../ton/tonlib-src/test/test-hello-world.cpp | 22 + .../tl/generate/auto/tl/lite_api.cpp | 314 ++ .../tonlib-src/tl/generate/auto/tl/lite_api.h | 126 + .../tl/generate/auto/tl/lite_api.hpp | 12 + .../tl/generate/auto/tl/ton_api.cpp | 1037 +++- .../tonlib-src/tl/generate/auto/tl/ton_api.h | 559 +- .../tl/generate/auto/tl/ton_api.hpp | 106 + .../tl/generate/auto/tl/ton_api_json.cpp | 543 +- .../tl/generate/auto/tl/ton_api_json.h | 44 + .../tl/generate/auto/tl/tonlib_api.cpp | 1600 ++++-- .../tl/generate/auto/tl/tonlib_api.h | 1397 +++-- .../tl/generate/auto/tl/tonlib_api.hpp | 416 +- .../tl/generate/auto/tl/tonlib_api_json.cpp | 1879 ++++--- .../tl/generate/auto/tl/tonlib_api_json.h | 194 +- .../tl/generate/scheme/.tonlib_api.tl.swp | Bin 16384 -> 0 bytes .../tonlib-src/tl/generate/scheme/lite_api.tl | 4 + .../tl/generate/scheme/lite_api.tlo | Bin 11088 -> 12416 bytes .../tl/generate/scheme/storage_api.tl | 0 .../ton/tonlib-src/tl/generate/scheme/tmp.tl | 16 + .../tonlib-src/tl/generate/scheme/ton_api.tl | 41 +- .../tonlib-src/tl/generate/scheme/ton_api.tlo | Bin 54548 -> 58212 bytes .../tl/generate/scheme/tonlib_api.tl | 160 +- .../tl/generate/scheme/tonlib_api.tlo | Bin 18708 -> 21096 bytes .../tonlib-src/tl/generate/tl_writer_java.cpp | 11 +- .../tl/generate/tl_writer_jni_cpp.cpp | 7 +- .../tl/generate/tl_writer_jni_h.cpp | 5 +- .../tonlib-src/tl/generate/tl_writer_td.cpp | 8 +- submodules/ton/tonlib-src/ton/ton-types.h | 29 +- .../ton/tonlib-src/tonlib/test/offline.cpp | 213 +- .../ton/tonlib-src/tonlib/test/online.cpp | 258 +- .../tonlib-src/tonlib/tonlib/KeyStorage.cpp | 15 +- .../ton/tonlib-src/tonlib/tonlib/KeyStorage.h | 7 +- .../ton/tonlib-src/tonlib/tonlib/KeyValue.cpp | 24 +- .../ton/tonlib-src/tonlib/tonlib/KeyValue.h | 18 + .../ton/tonlib-src/tonlib/tonlib/LastConfig.h | 4 +- .../tonlib-src/tonlib/tonlib/TonlibClient.cpp | 2218 +++++--- .../tonlib-src/tonlib/tonlib/TonlibClient.h | 129 +- .../tonlib-src/tonlib/tonlib/TonlibError.h | 15 +- .../tonlib/tonlib/keys/SimpleEncryption.cpp | 101 +- .../tonlib/tonlib/keys/SimpleEncryption.h | 20 +- .../tonlib-src/tonlib/tonlib/tonlib-cli.cpp | 1003 ++-- 284 files changed, 31520 insertions(+), 7794 deletions(-) delete mode 100644 Wallet/Wallet.tulsiproj/Configs/Default.tulsigen delete mode 100644 Wallet/Wallet.tulsiproj/peter.tulsiconf-user delete mode 100644 Wallet/Wallet.tulsiproj/project.tulsiconf delete mode 100644 submodules/ton/tonlib-src.tar.gz create mode 100644 submodules/ton/tonlib-src/crypto/block/adjust-block.cpp create mode 100644 submodules/ton/tonlib-src/crypto/fift/lib/Color.fif create mode 100644 submodules/ton/tonlib-src/crypto/fift/lib/GetOpt.fif create mode 100644 submodules/ton/tonlib-src/crypto/func/test/a10.fc create mode 100644 submodules/ton/tonlib-src/crypto/func/test/a11.fc create mode 100644 submodules/ton/tonlib-src/crypto/func/test/a6_4.fc create mode 100644 submodules/ton/tonlib-src/crypto/func/test/a6_5.fc create mode 100644 submodules/ton/tonlib-src/crypto/func/test/c1.fc create mode 100644 submodules/ton/tonlib-src/crypto/func/test/c2.fc create mode 100644 submodules/ton/tonlib-src/crypto/func/test/c2_1.fc create mode 100644 submodules/ton/tonlib-src/crypto/func/test/w8.fc create mode 100644 submodules/ton/tonlib-src/crypto/func/test/w9.fc create mode 100644 submodules/ton/tonlib-src/crypto/smartcont/auto-dns.fif create mode 100644 submodules/ton/tonlib-src/crypto/smartcont/auto/dns-auto-code.cpp create mode 100644 submodules/ton/tonlib-src/crypto/smartcont/auto/dns-auto-code.fif create mode 100644 submodules/ton/tonlib-src/crypto/smartcont/auto/dns-manual-code.cpp create mode 100644 submodules/ton/tonlib-src/crypto/smartcont/auto/dns-manual-code.fif create mode 100644 submodules/ton/tonlib-src/crypto/smartcont/dns-auto-code.fc create mode 100644 submodules/ton/tonlib-src/crypto/smartcont/dns-manual-code.fc create mode 100644 submodules/ton/tonlib-src/crypto/smartcont/manual-dns-manage.fif create mode 100644 submodules/ton/tonlib-src/crypto/smartcont/new-auto-dns.fif create mode 100644 submodules/ton/tonlib-src/crypto/smartcont/new-manual-dns.fif create mode 100644 submodules/ton/tonlib-src/crypto/smc-envelope/HighloadWallet.cpp create mode 100644 submodules/ton/tonlib-src/crypto/smc-envelope/HighloadWallet.h create mode 100644 submodules/ton/tonlib-src/crypto/smc-envelope/HighloadWalletV2.cpp create mode 100644 submodules/ton/tonlib-src/crypto/smc-envelope/HighloadWalletV2.h create mode 100644 submodules/ton/tonlib-src/crypto/smc-envelope/ManualDns.cpp create mode 100644 submodules/ton/tonlib-src/crypto/smc-envelope/ManualDns.h create mode 100644 submodules/ton/tonlib-src/crypto/smc-envelope/WalletInterface.h create mode 100644 submodules/ton/tonlib-src/crypto/test/fift/testdict2.fif create mode 100644 submodules/ton/tonlib-src/crypto/vm/memo.cpp create mode 100644 submodules/ton/tonlib-src/crypto/vm/memo.h create mode 100644 submodules/ton/tonlib-src/crypto/vm/utils.cpp create mode 100644 submodules/ton/tonlib-src/crypto/vm/utils.h create mode 100644 submodules/ton/tonlib-src/crypto/vm/vm.cpp create mode 100644 submodules/ton/tonlib-src/crypto/vm/vm.h create mode 100644 submodules/ton/tonlib-src/tdutils/td/utils/StealingQueue.h create mode 100644 submodules/ton/tonlib-src/tdutils/td/utils/port/rlimit.cpp create mode 100644 submodules/ton/tonlib-src/tdutils/td/utils/port/rlimit.h create mode 100644 submodules/ton/tonlib-src/tdutils/test/StealingQueue.cpp delete mode 100644 submodules/ton/tonlib-src/tl/generate/scheme/.tonlib_api.tl.swp create mode 100644 submodules/ton/tonlib-src/tl/generate/scheme/storage_api.tl create mode 100644 submodules/ton/tonlib-src/tl/generate/scheme/tmp.tl diff --git a/Wallet/Info.plist b/Wallet/Info.plist index e33b51058a..7e6af0fec1 100644 --- a/Wallet/Info.plist +++ b/Wallet/Info.plist @@ -38,8 +38,12 @@ $(PRODUCT_NAME) CFBundlePackageType APPL + CFBundleShortVersionString + $(PRODUCT_BUNDLE_SHORT_VERSION) CFBundleSignature ???? + CFBundleVersion + ${BUILD_NUMBER} ITSAppUsesNonExemptEncryption LSRequiresIPhoneOS diff --git a/Wallet/Wallet.tulsiproj/Configs/Default.tulsigen b/Wallet/Wallet.tulsiproj/Configs/Default.tulsigen deleted file mode 100644 index 127fcc96b5..0000000000 --- a/Wallet/Wallet.tulsiproj/Configs/Default.tulsigen +++ /dev/null @@ -1,61 +0,0 @@ -{ - "additionalFilePaths" : [ - "Wallet/BUILD" - ], - "buildTargets" : [ - "//Wallet:Lib", - "//Wallet:Main", - "//Wallet:Wallet", - ], - "optionSet" : { - "BazelBuildOptionsDebug" : { - "p" : "$(inherited) --features=swift.use_global_module_cache --features=swift.swift.no_generated_header --spawn_strategy=standalone --strategy=SwiftCompile=standalone --define=wallet_bundle_id=org.ton.TonWallet-iOS" - }, - "BazelBuildOptionsRelease" : { - "p" : "$(inherited)" - }, - "BazelBuildStartupOptionsDebug" : { - "p" : "$(inherited)" - }, - "BazelBuildStartupOptionsRelease" : { - "p" : "$(inherited)" - }, - "BuildActionPostActionScript" : { - "p" : "$(inherited)" - }, - "BuildActionPreActionScript" : { - "p" : "$(inherited)" - }, - "CommandlineArguments" : { - "p" : "$(inherited)" - }, - "EnvironmentVariables" : { - "p" : "$(inherited)" - }, - "LaunchActionPostActionScript" : { - "p" : "$(inherited)" - }, - "LaunchActionPreActionScript" : { - "p" : "$(inherited)" - }, - "ProjectGenerationBazelStartupOptions" : { - "p" : "$(inherited)" - }, - "ProjectPrioritizesSwift" : { - "p" : "YES" - }, - "TestActionPostActionScript" : { - "p" : "$(inherited)" - }, - "TestActionPreActionScript" : { - "p" : "$(inherited)" - } - }, - "projectName" : "Wallet", - "sourceFilters" : [ - "Wallet", - "Wallet/Sources", - "Wallet/SupportFiles", - "submodules/...", - ] -} diff --git a/Wallet/Wallet.tulsiproj/peter.tulsiconf-user b/Wallet/Wallet.tulsiproj/peter.tulsiconf-user deleted file mode 100644 index 4cae5c3523..0000000000 --- a/Wallet/Wallet.tulsiproj/peter.tulsiconf-user +++ /dev/null @@ -1,10 +0,0 @@ -{ - "optionSet" : { - "BazelPath" : { - "p" : "/usr/local/bin/bazel" - }, - "WorkspaceRootPath" : { - "p" : "/Users/peter/build/telegram-temp/telegram-ios" - } - } -} diff --git a/Wallet/Wallet.tulsiproj/project.tulsiconf b/Wallet/Wallet.tulsiproj/project.tulsiconf deleted file mode 100644 index 59fbd3b6ac..0000000000 --- a/Wallet/Wallet.tulsiproj/project.tulsiconf +++ /dev/null @@ -1,14 +0,0 @@ -{ - "configDefaults" : { - "optionSet" : { - "ProjectPrioritizesSwift" : { - "p" : "YES" - } - } - }, - "packages" : [ - "Wallet" - ], - "projectName" : "Wallet", - "workspaceRoot" : "../.." -} diff --git a/submodules/TonBinding/Sources/TON.h b/submodules/TonBinding/Sources/TON.h index 2a373115f0..85a37142a9 100644 --- a/submodules/TonBinding/Sources/TON.h +++ b/submodules/TonBinding/Sources/TON.h @@ -39,15 +39,43 @@ NS_ASSUME_NONNULL_BEGIN @end +@protocol TONTransactionMessageContents + +@end + +@interface TONTransactionMessageContentsRawData : NSObject + +@property (nonatomic, strong, readonly) NSData * _Nonnull data; + +- (instancetype)initWithData:(NSData * _Nonnull)data; + +@end + +@interface TONTransactionMessageContentsPlainText : NSObject + +@property (nonatomic, strong, readonly) NSString * _Nonnull text; + +- (instancetype)initWithText:(NSString * _Nonnull)text; + +@end + +@interface TONTransactionMessageContentsEncryptedText : NSObject + +@property (nonatomic, strong, readonly) NSData * _Nonnull data; + +- (instancetype)initWithData:(NSData * _Nonnull)data; + +@end + @interface TONTransactionMessage : NSObject @property (nonatomic, readonly) int64_t value; @property (nonatomic, strong, readonly) NSString * _Nonnull source; @property (nonatomic, strong, readonly) NSString * _Nonnull destination; -@property (nonatomic, strong, readonly) NSString * _Nonnull textMessage; +@property (nonatomic, strong, readonly) id _Nonnull contents; @property (nonatomic, strong, readonly) NSData * _Nonnull bodyHash; -- (instancetype)initWithValue:(int64_t)value source:(NSString * _Nonnull)source destination:(NSString * _Nonnull)destination textMessage:(NSString * _Nonnull)textMessage bodyHash:(NSData * _Nonnull)bodyHash; +- (instancetype)initWithValue:(int64_t)value source:(NSString * _Nonnull)source destination:(NSString * _Nonnull)destination contents:(id _Nonnull)contents bodyHash:(NSData * _Nonnull)bodyHash; @end @@ -87,10 +115,10 @@ NS_ASSUME_NONNULL_BEGIN @interface TONSendGramsQueryFees : NSObject -@property (nonatomic, strong, readonly) TONFees *sourceFees; -@property (nonatomic, strong, readonly) TONFees *destinationFees; +@property (nonatomic, strong, readonly) TONFees * _Nonnull sourceFees; +@property (nonatomic, strong, readonly) NSArray * _Nonnull destinationFees; -- (instancetype)initWithSourceFees:(TONFees *)sourceFees destinationFees:(TONFees *)destinationFees; +- (instancetype)initWithSourceFees:(TONFees * _Nonnull)sourceFees destinationFees:(NSArray * _Nonnull)destinationFees; @end diff --git a/submodules/TonBinding/Sources/TON.mm b/submodules/TonBinding/Sources/TON.mm index 5fcbc52b53..9349077739 100644 --- a/submodules/TonBinding/Sources/TON.mm +++ b/submodules/TonBinding/Sources/TON.mm @@ -48,14 +48,38 @@ static TONTransactionMessage * _Nullable parseTransactionMessage(tonlib_api::obj } NSString *source = readString(message->source_); NSString *destination = readString(message->destination_); - NSString *textMessage = readString(message->message_); + + id contents = nil; + if (message->msg_data_->get_id() == tonlib_api::msg_dataRaw::ID) { + auto msgData = tonlib_api::move_object_as(message->msg_data_); + contents = [[TONTransactionMessageContentsRawData alloc] initWithData:makeData(msgData->body_)]; + } else if (message->msg_data_->get_id() == tonlib_api::msg_dataText::ID) { + auto msgData = tonlib_api::move_object_as(message->msg_data_); + NSString *text = readString(msgData->text_); + if (text == nil) { + contents = [[TONTransactionMessageContentsPlainText alloc] initWithText:@""]; + } else { + contents = [[TONTransactionMessageContentsPlainText alloc] initWithText:text]; + } + } else if (message->msg_data_->get_id() == tonlib_api::msg_dataDecryptedText::ID) { + auto msgData = tonlib_api::move_object_as(message->msg_data_); + NSString *text = readString(msgData->text_); + if (text == nil) { + contents = [[TONTransactionMessageContentsPlainText alloc] initWithText:@""]; + } else { + contents = [[TONTransactionMessageContentsPlainText alloc] initWithText:text]; + } + } else if (message->msg_data_->get_id() == tonlib_api::msg_dataEncryptedText::ID) { + auto msgData = tonlib_api::move_object_as(message->msg_data_); + contents = [[TONTransactionMessageContentsEncryptedText alloc] initWithData:makeData(msgData->text_)]; + } else { + contents = [[TONTransactionMessageContentsRawData alloc] initWithData:[NSData data]]; + } + if (source == nil || destination == nil) { return nil; } - if (textMessage == nil) { - textMessage = @""; - } - return [[TONTransactionMessage alloc] initWithValue:message->value_ source:source destination:destination textMessage:textMessage bodyHash:makeData(message->body_hash_)]; + return [[TONTransactionMessage alloc] initWithValue:message->value_ source:source destination:destination contents:contents bodyHash:makeData(message->body_hash_)]; } @implementation TONKey @@ -100,15 +124,51 @@ static TONTransactionMessage * _Nullable parseTransactionMessage(tonlib_api::obj @end +@implementation TONTransactionMessageContentsRawData + +- (instancetype)initWithData:(NSData * _Nonnull)data { + self = [super init]; + if (self != nil) { + _data = data; + } + return self; +} + +@end + +@implementation TONTransactionMessageContentsPlainText + +- (instancetype)initWithText:(NSString * _Nonnull)text { + self = [super init]; + if (self != nil) { + _text = text; + } + return self; +} + +@end + +@implementation TONTransactionMessageContentsEncryptedText + +- (instancetype)initWithData:(NSData * _Nonnull)data { + self = [super init]; + if (self != nil) { + _data = data; + } + return self; +} + +@end + @implementation TONTransactionMessage -- (instancetype)initWithValue:(int64_t)value source:(NSString * _Nonnull)source destination:(NSString * _Nonnull)destination textMessage:(NSString * _Nonnull)textMessage bodyHash:(NSData * _Nonnull)bodyHash { +- (instancetype)initWithValue:(int64_t)value source:(NSString * _Nonnull)source destination:(NSString * _Nonnull)destination contents:(id _Nonnull)contents bodyHash:(NSData * _Nonnull)bodyHash { self = [super init]; if (self != nil) { _value = value; _source = source; _destination = destination; - _textMessage = textMessage; + _contents = contents; _bodyHash = bodyHash; } return self; @@ -164,7 +224,7 @@ static TONTransactionMessage * _Nullable parseTransactionMessage(tonlib_api::obj @implementation TONSendGramsQueryFees -- (instancetype)initWithSourceFees:(TONFees *)sourceFees destinationFees:(TONFees *)destinationFees { +- (instancetype)initWithSourceFees:(TONFees * _Nonnull)sourceFees destinationFees:(NSArray * _Nonnull)destinationFees { self = [super init]; if (self != nil) { _sourceFees = sourceFees; @@ -582,11 +642,14 @@ typedef enum { } }]; - auto query = make_object( - make_object( - makeString(publicKeyData), - initialWalletId - ) + auto initialAccountState = make_object( + makeString(publicKeyData), + initialWalletId + ); + + auto query = make_object( + tonlib_api::move_object_as(initialAccountState), + 1 ); _client->send({ requestId, std::move(query) }); @@ -604,36 +667,31 @@ typedef enum { if (object->get_id() == tonlib_api::error::ID) { auto error = tonlib_api::move_object_as(object); [subscriber putError:[[TONError alloc] initWithText:[[NSString alloc] initWithUTF8String:error->message_.c_str()]]]; - } else if (object->get_id() == tonlib_api::generic_accountStateUninited::ID) { - auto result = tonlib_api::move_object_as(object); - TONTransactionId *lastTransactionId = nil; - if (result->account_state_->last_transaction_id_ != nullptr) { - lastTransactionId = [[TONTransactionId alloc] initWithLt:result->account_state_->last_transaction_id_->lt_ transactionHash:makeData(result->account_state_->last_transaction_id_->hash_)]; + } else if (object->get_id() == tonlib_api::fullAccountState::ID) { + auto fullAccountState = tonlib_api::move_object_as(object); + int32_t seqNo = -1; + if (fullAccountState->account_state_->get_id() == tonlib_api::uninited_accountState::ID) { + seqNo = -1; + } else if (fullAccountState->account_state_->get_id() == tonlib_api::wallet_v3_accountState::ID) { + auto v3AccountState = tonlib_api::move_object_as(fullAccountState->account_state_); + seqNo = v3AccountState->seqno_; + } else { + [subscriber putError:[[TONError alloc] initWithText:@"Unknown type"]]; + return; } - [subscriber putNext:[[TONAccountState alloc] initWithIsInitialized:false balance:result->account_state_->balance_ seqno:-1 lastTransactionId:lastTransactionId syncUtime:result->account_state_->sync_utime_]]; - [subscriber putCompletion]; - } else if (object->get_id() == tonlib_api::generic_accountStateWallet::ID) { - auto result = tonlib_api::move_object_as(object); + TONTransactionId *lastTransactionId = nil; - if (result->account_state_->last_transaction_id_ != nullptr) { - lastTransactionId = [[TONTransactionId alloc] initWithLt:result->account_state_->last_transaction_id_->lt_ transactionHash:makeData(result->account_state_->last_transaction_id_->hash_)]; + if (fullAccountState->last_transaction_id_ != nullptr) { + lastTransactionId = [[TONTransactionId alloc] initWithLt:fullAccountState->last_transaction_id_->lt_ transactionHash:makeData(fullAccountState->last_transaction_id_->hash_)]; } - [subscriber putNext:[[TONAccountState alloc] initWithIsInitialized:true balance:result->account_state_->balance_ seqno:result->account_state_->seqno_ lastTransactionId:lastTransactionId syncUtime:result->account_state_->sync_utime_]]; + [subscriber putNext:[[TONAccountState alloc] initWithIsInitialized:false balance:fullAccountState->balance_ seqno:-1 lastTransactionId:lastTransactionId syncUtime:fullAccountState->sync_utime_]]; [subscriber putCompletion]; - } else if (object->get_id() == tonlib_api::generic_accountStateWalletV3::ID) { - auto result = tonlib_api::move_object_as(object); - TONTransactionId *lastTransactionId = nil; - if (result->account_state_->last_transaction_id_ != nullptr) { - lastTransactionId = [[TONTransactionId alloc] initWithLt:result->account_state_->last_transaction_id_->lt_ transactionHash:makeData(result->account_state_->last_transaction_id_->hash_)]; - } - [subscriber putNext:[[TONAccountState alloc] initWithIsInitialized:true balance:result->account_state_->balance_ seqno:result->account_state_->seqno_ lastTransactionId:lastTransactionId syncUtime:result->account_state_->sync_utime_]]; - [subscriber putCompletion]; - }else { + } else { assert(false); } }]; - auto query = make_object(make_object(accountAddress.UTF8String)); + auto query = make_object(make_object(accountAddress.UTF8String)); _client->send({ requestId, std::move(query) }); return [[SBlockDisposable alloc] initWithBlock:^{ @@ -681,7 +739,21 @@ typedef enum { } }]; - auto query = make_object( + auto inputMessageData = make_object( + makeString(textMessage) + ); + std::vector > inputMessages; + inputMessages.push_back(make_object( + make_object(address.UTF8String), + amount, + tonlib_api::move_object_as(inputMessageData) + )); + auto inputAction = make_object( + std::move(inputMessages), + forceIfDestinationNotInitialized + ); + + auto query = make_object( make_object( make_object( makeString(publicKeyData), @@ -690,11 +762,8 @@ typedef enum { makeSecureString(localPassword) ), make_object(fromAddress.UTF8String), - make_object(address.UTF8String), - amount, timeout, - forceIfDestinationNotInitialized, - makeString(textMessage) + tonlib_api::move_object_as(inputAction) ); _client->send({ requestId, std::move(query) }); @@ -723,14 +792,25 @@ typedef enum { } }]; - auto query = make_object( - make_object(), - make_object(fromAddress.UTF8String), + auto inputMessageData = make_object( + makeString(textMessage) + ); + std::vector > inputMessages; + inputMessages.push_back(make_object( make_object(address.UTF8String), amount, + tonlib_api::move_object_as(inputMessageData) + )); + auto inputAction = make_object( + std::move(inputMessages), + forceIfDestinationNotInitialized + ); + + auto query = make_object( + make_object(), + make_object(fromAddress.UTF8String), timeout, - forceIfDestinationNotInitialized, - makeString(textMessage) + tonlib_api::move_object_as(inputAction) ); _client->send({ requestId, std::move(query) }); @@ -751,7 +831,12 @@ typedef enum { } else if (object->get_id() == tonlib_api::query_fees::ID) { auto result = tonlib_api::move_object_as(object); TONFees *sourceFees = [[TONFees alloc] initWithInFwdFee:result->source_fees_->in_fwd_fee_ storageFee:result->source_fees_->storage_fee_ gasFee:result->source_fees_->gas_fee_ fwdFee:result->source_fees_->fwd_fee_]; - TONFees *destinationFees = [[TONFees alloc] initWithInFwdFee:result->destination_fees_->in_fwd_fee_ storageFee:result->destination_fees_->storage_fee_ gasFee:result->destination_fees_->gas_fee_ fwdFee:result->destination_fees_->fwd_fee_]; + NSMutableArray *destinationFees = [[NSMutableArray alloc] init]; + for (auto &fee : result->destination_fees_) { + TONFees *destinationFee = [[TONFees alloc] initWithInFwdFee:fee->in_fwd_fee_ storageFee:fee->storage_fee_ gasFee:fee->gas_fee_ fwdFee:fee->fwd_fee_]; + [destinationFees addObject:destinationFee]; + } + [subscriber putNext:[[TONSendGramsQueryFees alloc] initWithSourceFees:sourceFees destinationFees:destinationFees]]; [subscriber putCompletion]; } else { @@ -978,6 +1063,7 @@ typedef enum { }]; auto query = make_object( + make_object(), make_object( makeString(addressData) ), diff --git a/submodules/WalletCore/Sources/WalletCore.swift b/submodules/WalletCore/Sources/WalletCore.swift index b39f7dd95a..bca23575fc 100644 --- a/submodules/WalletCore/Sources/WalletCore.swift +++ b/submodules/WalletCore/Sources/WalletCore.swift @@ -1060,18 +1060,73 @@ private extension WalletTransactionId { } } +public enum WalletTransactionMessageContentsDecodingError: Error { + case generic +} + +public enum WalletTransactionMessageContents: Codable, Equatable { + enum Key: CodingKey { + case raw + case plainText + case encryptedText + } + + case raw(Data) + case plainText(String) + case encryptedText(Data) + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: Key.self) + if let data = try? container.decode(Data.self, forKey: .raw) { + self = .raw(data) + } else if let plainText = try? container.decode(String.self, forKey: .plainText) { + self = .plainText(plainText) + } else if let encryptedText = try? container.decode(Data.self, forKey: .encryptedText) { + self = .encryptedText(encryptedText) + } else { + throw WalletTransactionMessageContentsDecodingError.generic + } + } + + public func encode(to encoder: Encoder) throws { + var container = try encoder.container(keyedBy: Key.self) + switch self { + case let .raw(data): + try container.encode(data, forKey: .raw) + case let .plainText(text): + try container.encode(text, forKey: .plainText) + case let .encryptedText(data): + try container.encode(data, forKey: .encryptedText) + } + } +} + +private extension WalletTransactionMessageContents { + init(tonTransactionMessageContents: TONTransactionMessageContents) { + if let raw = tonTransactionMessageContents as? TONTransactionMessageContentsRawData { + self = .raw(raw.data) + } else if let plainText = tonTransactionMessageContents as? TONTransactionMessageContentsPlainText { + self = .plainText(plainText.text) + } else if let encryptedText = tonTransactionMessageContents as? TONTransactionMessageContentsEncryptedText { + self = .encryptedText(encryptedText.data) + } else { + self = .raw(Data()) + } + } +} + public final class WalletTransactionMessage: Codable, Equatable { public let value: Int64 public let source: String public let destination: String - public let textMessage: String + public let contents: WalletTransactionMessageContents public let bodyHash: Data - init(value: Int64, source: String, destination: String, textMessage: String, bodyHash: Data) { + init(value: Int64, source: String, destination: String, contents: WalletTransactionMessageContents, bodyHash: Data) { self.value = value self.source = source self.destination = destination - self.textMessage = textMessage + self.contents = contents self.bodyHash = bodyHash } @@ -1085,7 +1140,7 @@ public final class WalletTransactionMessage: Codable, Equatable { if lhs.destination != rhs.destination { return false } - if lhs.textMessage != rhs.textMessage { + if lhs.contents != rhs.contents { return false } if lhs.bodyHash != rhs.bodyHash { @@ -1097,7 +1152,7 @@ public final class WalletTransactionMessage: Codable, Equatable { private extension WalletTransactionMessage { convenience init(tonTransactionMessage: TONTransactionMessage) { - self.init(value: tonTransactionMessage.value, source: tonTransactionMessage.source, destination: tonTransactionMessage.destination, textMessage: tonTransactionMessage.textMessage, bodyHash: tonTransactionMessage.bodyHash) + self.init(value: tonTransactionMessage.value, source: tonTransactionMessage.source, destination: tonTransactionMessage.destination, contents: WalletTransactionMessageContents(tonTransactionMessageContents: tonTransactionMessage.contents), bodyHash: tonTransactionMessage.bodyHash) } } diff --git a/submodules/WalletUI/Sources/WalletInfoTransactionItem.swift b/submodules/WalletUI/Sources/WalletInfoTransactionItem.swift index cef12fb45c..2240a179a7 100644 --- a/submodules/WalletUI/Sources/WalletInfoTransactionItem.swift +++ b/submodules/WalletUI/Sources/WalletInfoTransactionItem.swift @@ -242,7 +242,14 @@ class WalletInfoTransactionItemNode: ListViewItemNode { if !description.isEmpty { description.append("\n") } - description.append(message.textMessage) + switch message.contents { + case .raw: + break + case .encryptedText: + description.append("") + case let .plainText(text): + description.append(text) + } } } case let .pending(transaction): @@ -268,7 +275,14 @@ class WalletInfoTransactionItemNode: ListViewItemNode { case let .completed(transaction): if let inMessage = transaction.inMessage { text = formatAddress(inMessage.source) - description = inMessage.textMessage + switch inMessage.contents { + case .raw: + description = "" + case .encryptedText: + description = "" + case let .plainText(text): + description = text + } } else { text = "" } diff --git a/submodules/WalletUI/Sources/WalletTransactionInfoScreen.swift b/submodules/WalletUI/Sources/WalletTransactionInfoScreen.swift index 6d420a7ded..5aea1460da 100644 --- a/submodules/WalletUI/Sources/WalletTransactionInfoScreen.swift +++ b/submodules/WalletUI/Sources/WalletTransactionInfoScreen.swift @@ -106,11 +106,25 @@ private func extractDescription(_ walletTransaction: WalletInfoTransaction) -> S if !text.isEmpty { text.append("\n\n") } - text.append(message.textMessage) + switch message.contents { + case .raw: + break + case .encryptedText: + text.append("") + case let .plainText(plainText): + text.append(plainText) + } } } else { if let inMessage = walletTransaction.inMessage { - text = inMessage.textMessage + switch inMessage.contents { + case .raw: + text = "" + case .encryptedText: + text = "" + case let .plainText(plainText): + text = plainText + } } } return text diff --git a/submodules/ton/BUILD b/submodules/ton/BUILD index 15e274e8b9..a78da4452a 100644 --- a/submodules/ton/BUILD +++ b/submodules/ton/BUILD @@ -35,12 +35,19 @@ ton_lib_names = [ "tonlib", ] +filegroup( + name = "TonSources", + srcs = glob([ + "tonlib-src/**/*" + ]), +) + genrule( name = "ton_build", srcs = [ "build-ton-bazel.sh", "iOS-bazel.cmake", - "tonlib-src.tar.gz", + ":TonSources", "//submodules/openssl:openssl_include", "//submodules/openssl:libcrypto.a", ], @@ -70,7 +77,10 @@ genrule( cp $(location :build-ton-bazel.sh) "$$BUILD_DIR/" cp $(location :iOS-bazel.cmake) "$$BUILD_DIR/" - tar -xzf $(location tonlib-src.tar.gz) -C "$$BUILD_DIR/" + + SOURCE_PATH="submodules/tonlib/tonlib-src" + + cp -R "$$SOURCE_PATH" "$$BUILD_DIR/" mkdir -p "$$BUILD_DIR/openssl_headers/include/openssl" mkdir -p "$$BUILD_DIR/openssl_headers/lib" diff --git a/submodules/ton/tonlib-src.tar.gz b/submodules/ton/tonlib-src.tar.gz deleted file mode 100644 index e9f5ac49de0a6a24939c295629a1fa45f113a1b3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1490956 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
  • hqL$8qiHDTptJV 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

    |p@9lA2YADTX1q`%>VL{t|SDQ-8U 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

    9caSv$YcqZ$3M2m4zypoe>Z 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 a^v1Lv^gU=-X7!Z&3oj>^z?H=&VefV8Fm_=D^I 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

    qDf01e8=UY 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

  • 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�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

    V+CyR9@`-*KMrT_*wu9S z0cd3?j-uNp-mW#BfQ$((avQyW^#94PvhnbWxu~z+R{-;KD26OQPCgbgyJpNCXEgXU z1rl~1rI+@kb_&YJ*oFrwY~Ry;tXF|?>(Q)*NqY$`MRt5}&aOWdh}K-Q#0~ z$NTvn8&5v!alb1b65CD_m}BQhgkygv9bSyFbpk3bEe2vNgN`zD-6bsPhs|bi5M#}F z4mgmK^UuIdb@-nMF_V|$pFP-spG~`$fcG;mg1awK^H@*?NK=C>7*3doNLX?WjTl2C z{1k>TLwa|Q9@Er(d`-_J%i%!7+Z{HW_ujL|N5qEvJJmCIj~A=T(GsgDP5Z6O07d)% zyWzz<;!-Yc)jot`>i3qz0YlSjG;;U!3w{Q3VZG7(EXMak%A3oLk^VugM zR@3qfdq~P)eHo_%JeE|G{fqrQdc*mI@2I^`FhlrOobFZtShv?pu0R-{O#5^vC6tGm z0n8pY8+=7DCKG^F7#;w|&aR_zxZkVzUPzqPy{sbzHCo|ai60ztYnrU)1>VASf zdotq+)%y&Uz)82ihx_m}ktZy4)tx3i5C<4-8u1Wzp!-;w;|4o9YHGYEI@i-NsWm5`6B>HJ)r zw1&`&vaP#Nu-Z#G99)8{QMe1suKA?Z*j12Gi0ES-*cE{I2M=IBpqI0E)5*tpIH*QV z4IShgs-UX(kuda2LWkYz?moAXl6X+v)ufVK7b}YQ*a)34d!wWaN8~+rH9v=Liebau zW0O%oMs!19TBNI=X-nT}i}M7InZ_f`4N~RJ?Wg-_`!tBF#(P8{=_MZ`Is^Ou9P7r= zxQBqn=wZ8e!aZ4CKcA0Bz!TL7YMGemA5x(VaDi|TMsFr?@?>@ zYS4nIO`rhSfK{QS)b?P-OO%TaZNBV?;^GpMY4@X|NtOc%r3!7w+M@6mJf<`5fK>e_ z5QL98SJ!}jS`Eq5j3zPh94>n>O<^5OG0uC4hmK1!^}}k35wJq`W!;MjKr@))pPVVs z_;fxWj$j?Ncmu=~ngAH)Sk+@8D%<>J^(##im=*<{{(SM_)N04LPYn#8;VGbIg-HvS*v5ScR=7pH>JNagxqb`BNa=idG_`q@PS zMlDmyUO1rLnG)t=f@^_UfM$WY!tj^KZEDD16$d_f23zfAGJ7|{6A=97`n(h)`sn(U z>7)m&2~8J}P>!Vyb*x_Pu|Pa}4~y#<`gbzDn9OF$c(;PnOBH-r9U8mUuE2{6hTJI1 zEwiz^uEt++IbCKo<(1&H;H~uM-|KSugn+`ESg**YQ zB>pdw|09t4GxC4qR{r102bP^vHOx}}uXb^c4N(^{88Cb7Ny_JoudS^^iT4sa5!SDW zfgGLU`YO)@N`3}@`-JBKt;^`$fQ%e7&Abn*c(xb~$66@9La{)o6p-vHkZi6JiBg?7LS2M;7IC}t>nNcM&z{zZ2% z>RzO-Aj5ZK+EVHDf3S|+TA`1!=aw#XV0Q#(o0RL|sHA8vwh^IyQNnc0^(KA#*OK>v zN_to|B!2x&Zxq6rfPu;~!vta#etL>aPqiTxLM+nn9iJ|skYOtsuRSKx2KeRvGl z-6I*$C+z2lXg=wT@ZDtrNoPf3mn~Eo49!t~@g0`dJofmSh9e@E8|Z&)<&p2@a_6i& zfiuAN!h&t&$0<|f{`d~{hQN9IoOW19Qs@9f$}c+j(EIelcunUW{c`di-pLh#uQ0Mj zhU|`oa#lIf)Qspqd9Ukd4qsH$J#u+Zk~hsp9@%^-ttC}ga2EWQH(xXR1c66z=iO0v z+)MHR+Pl|75d7~E5>;(~Fr22d>e@nTk^DDKKGqx^@Ja^Y1@_;l(QLW$Uli7F<-cuw zO51<4#-l=u@W;vYeeYd&IIa!*Xb_esZuu*1SZ5~LSq9je~WmO#WVgre&j+P_?Nq~cz2=tiL=h}qB8mom2P0pqz_)Z|~ zr{*}IAr&Mm?jD4}m+B??K4D+hZ{0dbRPmBKSy}O?_;no4$j6vd=2Q=C6kb zNZYX~Rn}0>re5IpnJ}i3RaVRu(Yt>qGrDV5ljiil3p0D(dp+~e9t#iA@>!R*Rg+G5 zG$b3R-{^dijFTyP_6X}UmQ>v+G|5*KO7VD)RnCuaaB+95;IRmQz`hEb#sN4`;&es($Ahf?=!(nq#dueckqv zP2^DL+UB{v-{>Gc@X9{`R}ASNQ2UTf&oMMf)gp1@-A1!TKR|B3kt>Xx0&FiM` z9X}@G_~U!-24L9JKO2v7Ozp?cNtMZ79KtE-cdlB1Rdb=$J!d4fi%pIlUX<*~1%t|e zE7tj&{}jo8+$qalhL*>%NdH%FWb}VQkanrd3=I_Bce`0cTkXx3)4zoV6 z%Ko7Dck8K#NuWgK_3110qQx`K)8i-4(K*@H@nv2}MGl>UjDp!%KRTyde!~?RBWMCD zs(4`g6Z1DLjt-k50PXox3R(P(UTf`3Qu zi;MTta4BjmEsv^gUSG9Db$!xSkd9wIJ>%*il_J>>)v9ZQ)dVd2OtG64?TlsGr zpPPyQK$`#^oOLY71AYtK5&LWHF?(=6>3@PVbnobI@cRjSAl*P~sDMhK*x!~99x+dH zT#;s|?8U*}xZX(26gpgufEn zOf&q0w~=0k@KxEID|aGaB+8uzyL0sH6d#D&4SCy}s?$kdX^wS4Y)WJX<&66^5=C&B z=?jjrmMHGAy8)|Fxnv5YeFA<=&^PRE2#-Msq(nZ`=>!-7AOPzGKuPPMeh{!9S#X!N zn$4(5j7q~FHp77Z1W(yr_HHuj^FIE9;W;qDhnINQ-gI(hu*A}#G`4c?jH^c%>E~9A zozdz`J|Z^X(%{&SXlg!YkB@M6;-E>!7YAFlGGR5zuLi3DEHoXW()o=jIz>Iwj=Y|8 zAJ}An2Udb^uSXAdD%zugnk@LP4I{vt3`;8Z2k#01Ogwj3zupnD5Syrsy@*X^iDX_?&;PbG5F(!8MGZ4P~HiidX=7qj|VZ9gf+p21=!O z(GYtVRh8s9YY;&_kk-&l@Q}RvQENQ;kW4wU8vgvuSy0y_tuhW)x+jO^{D_pLMhudk zN}V;Mj|xh!_S9e=_=g-8dJ^K zcl4O3;13HF{4UBo{b&Z~YU=-$(aAf=JjMZWV@GZaT~I}6P4e7|3){8?BB@Kx>iN0R zVUew40j{Nt9}8ef#WlZ#gc7KR3oH*lh@++oh`Zg|8piQwzcJ9VJc+92A8qI`EEhd zcT+5lPrwf}A9vnBt3!ys7J`JZzh`fBI9`x~)G%93E<+Gh&(snV%BzNOsX z6aDf@G0JUrHig<&$9PBpCv7Pc9ybqtFU&*Sq7~$(a^u#o%45LJoz!tD3LZQNYEU+4 zvLAmk%qyzBW(92!>6s4KU9Ss#omJ0e&0RriAV@6;BtRnB(!m5Ad?>(&!gtwYkt3bI zG{(_W-YvP20eo1Ni44#@mWc<*dio1HE3Z>|@EIkHH&0&UEgP?KSA+391qu4+H{at* zF3tqhJ%jFW#CQy%qralOMYiTkZ52=6oYEE{PXFx9+b6$}D0m`|@^n&QVwWNNRGN%f zDs~}g26fs!?=<12Z+VPGd|dLCzE7dNup$)j2^NQsPWXfZaf%9J^P)2aKdRaXX2~ez zYBhvSX4ZT6P}Jq;94VFMAd})bbTo=b6Lw)N`hzHo+q&4wvD@8p z_t_ODpGs$F7^Hhcd2UpB73}FNO+Aw>9mx@>7=ognij>gr@@n=;S?FjHk)Pr|%>49sI{Z{P*$ctK&23wTfylOu1?IqxR#+CEy8~MzI9eFeUOY zAk=umSoBmEkp(*VBscDao89bS6Jh7OkysPH0GP2RVi_qPYw}G6nAqk^qje>tJLK5y zygqsPY=_;s+2D@F5glSQ{#_$FmisJ{|5fV8HI4uaYm>gmrCg055RJ`ZK>_PbXzJCZdM zzzRaKDHEgIcY6E=J3!<$fCGbT0;Zze+>62m7aip_C0LcaKkZ=tgBnkkz@;u!TKQyU z5<_X@ACsPnOI|29YO(x(`=oMH2-iknW$q-(LNSW=+F#P%cPF zwADHkm?weNqjSh3=_cZFJO_bgp%ZN?3TNqv8WiOu2pv(Q%s#dmY(b1ng_$;)(%~Uk z_}4$3JU>>)E99hdkui-rXW^%>N=C*&89tGKyPnJAC_Mnl`}Fwi`1H@mq8vzw$@D`) z83@kjGZxe%arB@$j%f%)z7YD1i@%M5zYTo9{gnC?o&P{CpIr<;tZV*R zc>hlbqMu{`X|!+S|F`nlO#D}2yjSTst~c=SGvv30VN}K;PBH0H<`_K7Ma+Ac!xM+* z{A_d!tGuA=b%g2UdeA#R2)a=>>IAKReb7Gd^uk`d71TTDo$kSTui0X^edB1%y z=ycD6deCcz{qyi3jKZ*0ujq}LP>KuN_II#5_#q2mLNBPB^iH6Mw6?25ho+K7~HcUIOR4d<=^46IR1OZq~FG8 zLHtM1f)k?a|53k<|Jcgs{(W|4g-_dei~X^$uer_J?9bc0jikt%%voIes+NDzjKMcJ z|Ch}FyOJSr!TB$0M?v=fhuibtRzBZ!{@)MbZ3^Jq6u_&b0LCO2E&T%XSWMdY6zNu`&I#KPvjj80D z%qxud^U6s<{(TP~pl^ei*z!s&0Dht-3kon~grL^q+K9TA-}Ym5Q1>&Cs!V)zo2vNR zN>yCe|0`P0|EuWy-)v>{|F`~M+xl!t{#!x#bA6X+SDlZC!1W%{%Ea)^d5vvdKy!q% zO* z0*~!|w~9lZH;qFxDCuFBL()oqaehi#UPn1j-YTS#=N!45mI=D{`_rxER_7iEHg=Bu zw>dq2J4Z&(>2B`1istrE_lNSmD?0!27{?mFu(Fn3_EtOtF7p3sg_-!DcKi1JzpZ?3 zCjYna0b4qSw|%3uZHkt~alSweIBkqC7Sy0q1BKBhYyyX+-h4WRv(iXzet2@BV}xLF zd5YK*+W%GZh3^>&!xv-%7g(3^TN9ZB!raUOmCB9)dr4kuJH9hr-OM+QvL&qI>dCNw z?a!yZMVu zBWXmfL94+xTf=h=)y!(_?@FO?^+e37TgoJ2Hiqvu5p&+B@cuWM@O4cb#rof{3ERGV z|3~vy|GS+J`hUTS)9+6E;`H>1mgd2H{G@XKKCGFODVnE$W3?mTV6jQ3)!*2=q}$&U zk7iwTtLmngYzK2t?A*7iReuxZb{T9WSew@x4bz#Z_4cK&9u?bTzwJ`dcnq`9ty;x` z0juxk!1#^zy3;JaCy!2{plDCuSK#TX0cnr@MYkVUYiR#9KKvw#zkYP$DUS{R3pSdn zh^|sC&eqvu|EU;O3K)2Esvt()F?iN}wgKYID(SVBhMGwz>9_aXE|Dbxx+c?*Te|4cjaalENf z>P(fI;dK?hVrPGP6gFFL6-viP5T9YKJtnGY|3G|Y`Zn?zC6s^yF9(MT9M|uVv^q;d z#c7XDc+g$SWfRLM*FAK!9CDGWuiQ(;=%2p&_0j3Glb^9RRPE0%uVPr}d+)1u$)|5$ zygqyL3l^jP*4}&ky-;_`-mUYxv<1ARFhQ{P?lev>`@;^d_my36jhx4m8gCaW5I04ZT*?@Cunw>(T#Sq@o7Ab_UqGVWGNKB2q< zZz7!WIHnZ8n&?h`%Y`z}2V+8bD?|G8vcUWhiM z1+|{MePdT5Or!3?iiqy{qZ~?Ct8dH`)NSYYD<)`mXG*39jh!fIG|f{ENf8B&-G}_V zoq}klv9>6)jk3_=lQ%T`p_JeiUDgW~Dr5jtdbNjc$>SHV-~7cYN4t=}@Y8H*#GX_7 zRFrggd{-@gSV%tRuIRXqse*i@#j;xMVa=VhH)>V0 zYtrgqR5ey_HP^4%IsXA*Q#J(ZE)#~+e>{!dX{H`uB3#_6mRut2O2niK z`b%=GZ(T&QCdz5~Q|QInGfQrx-7H%Nj|Zo~cB-_&)w~Lvw0+f1kAFQqd2t^UX(@0QRMgFv*S0fUS~UTQ}ExK z@I|ljol5gYX*B{8I$Il%E^Nk{SD-f7soZ`g| z&=1|T1Dm9IErg41zBzPnbI|eb%eImC;)a?EJy{z4eBcxj}rk7;qDaPO=T#20jJ35RVKtUI|mSVOzv!ECV3#mEipqSOjE6 zFT!bZHR|@t>>ev1Jw1jqEU7lL+u}{N^d#HT;f=TSM7PwDQ^hHz3{rWZS#IJ#&J|X- zg4#KI+$hcyPjk17+FFVhqO_KX<&k=t`*l#;3zWoNY9_6~Sulb9xWx>|B1K##WHJ*mIXgG9B1u_)mg{_7U^Dofp!O1KFgOFT_WUKckkX->B#hj zD?Kky!^tN4Vz_=^EKP^0S`)poc4sWz7g-|2I=NnFtj!nMInupefj1xhw(&V~<8+jm zBg@iovWdR%%#j`NP_^;?Lb_J$ui;Jc*U38kHM}|gI$4ju zhBw7uC+qOn@aFjIWEuV)ZduP`zqa-vk&jxDzsETfFa{EhH+?oPXx+}%cd zSpIzS?A7ZxuOFR0dLiAZph}FsXb#+yGwG0qdH1>>W0CZqAo2vIyjv)Tn&p6_?+f7m zI!0}bQ=WE($&p7@^oB{g7}9UjtI191hBRNM7kLnLG^F7c1*NL0&wHLaZ=Sq*daQkt zC?B1$LEF~Sm)wtvGZh`77nS|me!H9cl*|8d!}q_oTbcZyja&ckt$e<%`=4&FecH&i zPfOkQl$z;Z|2XM0{1>a5`7@e9Nc6bLGdOe_p5et9Bku*8oO@U8%U11b`2P>+l}v%@ z^2X8EZ{5p4jT%^(R}*M+FH5bu*QK&u!V>b_8r+S$2#a&~QA6B)q-$_mcny`oK{ZFE zZD3Aw%xZLptCi})Z8*;eAsb<5aiHV`qMu)$yk?S{$Vt$=kakPg8f6+Oq!E-&RK5qD zPb(srTJhmyk>O41AWuiI^fSr*uwJC9iyfgFB=5H5Ft!0x>O@!=c7qaz(Os>2|p$>;$1BBtI~wlS@m%@9rml@Iw~q^>8!7{_#z$F zzIu>;M?7_gE8`QHZ0q}gRjsSjfQxRm=eOGPuc$pYHQBts^K{v&wyD6*l=iEz%PXz( zG}SwoXe*O;En_0*YOP7R>`_vaG8&$H)X}znnacQe(A=I#g-8iaeV|p|&ra_IZK0~F z<11-ApdabgXozllSF?Bg!ED%jKZC8P65=oH?|VW)U73RLi#uP8IuBgqF1zoOm@J*J z#Nz|Kjb8Qwu12-58=l~8z+BtBzvIzLtF(hu#83n0c6ouG+Oy_`YR$WxjFV5|dSX<= z(55`*Tl($|EQFjjZ)PoAyc&v0MpGv5gIE@=hI&?-6=*@jT5sMy`6XvXGi&86ZG2(K zrO(FsgIWUotAG7hyhfNhV>L!TTDh6 z-c$DK&&Q{7KRKn*RxtUdBIhce-LV!b4^XYFD0 zisDIJ3Q>EEhzJ1rm2}6dlXdMu0@F*^?P<3O;v%&>5`_AGAlRF74tLektQ$Qs? z#ODhWX-_bF;TygLh%TUdf!cd;qKRZD2HPvFyfkaDyYzpn!85MP%f@-_|2{r_b$q6~ zmYh`J05|P^)MhrEoKIkWPzkKzOiPBRHH63MJUNBqyN5_YemjerX~;l87uET|<8Eh0 zx;N#m@POFt%s}=f;r_z!q2FP5j#BnNcddTqw7~w4d;h^=DtG<_?Vs%78FAGAj)Szu zN%f%9Kjv3xo0~Y68Y9?@Q(K{3=?m1dS1u4&g5#f?O|qu%84>}VlB^XC@#sa(TG2Kk zAn7tb`KW#!$xoql6q(Y|J^Hq`j1);Dy}3MI3ooZ1D-8d0*S7|%3ft2zFYuGdY%QK< zZ%7n#pWnj>(*;dNcn0U$lIhGzJ53;FnwofXOgXHFOODq)?sBaEkV255Vih+l_y_7( z+f;UwVn$!z1NP-Gvb`SOK(9AAA6kz^=ViAxH0;9wX>(u6yxFezgM?6iXOrV^C+>bN z&6KGeeN0J?+XuYtb+5YTL+CwXZ2ZX`sDEu8(yzE}r$XM0|(o*_Kg0}h0 z`iYeefI|WWO}>i9^ULorZF-&ZqBnC2AX0z`z5YHSeBv8Cn@wijk@05G#ST+K4b#$% z`JJT~{|xF`Yy<~p{Uz*>gq8*%>DN%&r|*brI;)*01KfxBBiKvi0|JoNU^n?a8DlL3 z(%?8l{!c^xsVf2q40JCy%mU_yEYF&}YjTUyoOpWt`0X>kj#5r@;-^E{IPNv!v%kNO z|5R{N1`i$tHIQF_%A{Q&$ z{4T2E-VWPE45!mxBAPZC^|>ZAW!2eaLRZG_Rs!8GO{*sz5K^lpW;G}1qMP#f^o<6a zi2|{Hg5O}J=)+f1vl_2ZSp7YT`*Xo6Ohk(52ZK>}W>%0tIoeu{RdheFA79Y2!ub`r z5`F`xl86HgyU(XaU^P?0O8M+DKyd(NfGKE~z1ReZ3oj;x<-~%pD85m+1^+sHH;wsB z6S*P>u(C0X+@Wt3iNG0c`WpQd;=jNcKSj3*tR(#i@_XgW`8;!;|CIDlQG)}768BTSk2QtQiw90gIGZKvm$h&;G{l@wvjzKVhSZ`Naszc`66b00z9ri>4Jdqs4H`QtH$@n#rQ# z70w))_1hS7K4s-X?iR4$(q^&WrU_z~;F3Z-NCf9-c~o`Y$XxC+?=R^XDb_-DsG+9e zabhw6)?+Q>!@}r5Jnr@GN-(ntMrqFg#*W&nP)nHFip2T(4oPN5k1L0jCec%VpXiso} zmw^}NkP20?(`ob*2)CSmCh)$z;RcN zDe*p98i0d&93uNWUt@%pI`})|Q!=+i`1i`|Uw(K!|L@nYfBU6*Iv5j{p$a`I5)-MI+jRXRpP8-1^IC(Ejk-sD9mjJNoHk>$kxLvke3mz`EHVBIbq+k+K&mVp-)6 zdo(QE<$R%yIp4mld^Sp(moH6bTGqg<(0T03;=1_XN?UmSv=`WyHFj?6HOH@oRg(+~(p}-^O#UNAo`xY%T_+h3tU|s@S3%!>RS^n<1 z4)*WnQ;SL9mFYe7^!Ukh^bJzFE3Q{J-|#p!!|IsK?26-l+#RPMlWFELVV+*nB+tA| zrqhX4#T85p3h*NFSla4n7jf$uQiFbBctDAGFWp4TB?|gjB+@18o#`g^znyn1j_5T? z8JTw?{{-#d*_VS03X+ng(g^>GE+Sg#Y=dpg>)s3VJZ`@^8x)*L6Vldn5a;M7=o7>DXt-|5XShjsjmrVi051$S?+p z9kf|voFWv8XWa`Dcm?_9EXgkneR^1@8ewCZDlBduh7EfHm8!zx7S$rhz;e}i&tmvO zlP?5_V6LECd;+$ae>yt;%pX1VNkwLrJ*THXl z0B5%~x+ag`??B(}KIYHNV(#`98<~|FYE2W*2czyqs`ou{gI=~o+=ltlj_gIwDv`#D zv*oJhd2bf8FW<|rG3~{8q=SF-+;N(psbJKk3UKIMTs{t(YC`j!U3mPOLoFac*-U-W zRYB{JubhuwK3!BL7Vfqa@6IM+zy16qHxg;w(y%x~M`N9F(B| zZ9tO0BIGN$R7Vw*<(dl?vB%GUkqk!9z8o#8rL%=mNw+idJIZ5|!ndMV_k6)oqEIUN}5)@Y0~-=s*Ja zId5baH^NxO3oEPQwWa#JQ9rE7PXBUr{QT^A4NBEswg_pcs-Q{qb>0Nd(5eVsf<$A@ za<&V`etrZEHeNO|i__%216E=4z|TzmOzpVQ&f^KUtm>ld94AoD#AXyRlv~OM={q(` zX(u1VOq@Mt{M=z7RzF_8`n5C!{aaOkc6$8iO;I~s5OFioJ>}hB?D|mNMPD8{R*stu zRYA%P-olgj&b(TRPNTNsnCuqe=Y+_+nYm4A9Y!rx<@A+R)+y#Nq^;jE#ANw%XiuYDLRHhBl$g;JB(svqj26@xf_1hJ^fS&<4P z5V6(>Vc(FYm^``2?F)g(XLUmrL-L0>w&1qT1t;F9*ROsRM_iDPc)_+M>EiRa)iFiG zxW)IYsO`}scvOR#6Oh!$xZ1Ti6#KeoSI5_mo=?t#=@I_Rm`Y=E!S>Ac+Q7>nTbbCBXqI5}}F>#eTX2wWSUkOD^ zR#qJCFisi5El?89^W(F#@(?7GM@_jS&`;A~QxcA|#FwhoOC@utGia%5+WHf><73 zm61?F6VdzYg41~n6=Zd6#uPgNW&bI}Vu8p(qbV^TyLyT>5Xd#ha_&*eo~Dmwt@_2N zj0J!vDOw$rH2ff0Exy!;qJ#Y{^MV5?273LDv$sfdv^-G3s13Idb$%mTX$AX4yWMFu z+qQ&J9;J8~H=2hUn8OxJwV)-mSn_;QzH(NRl{W$1{x+?Zizk`XTk6$dVI?}>#KJ5r z0qEsusrvl8WxcjEWyqIG&Wbd#<^UU@ZIlLVi)O|Ac#4xs7uTAd2h}ohTe_i@23Im~ zzF59I`@#v*k=a*e;AU1=w{$C4Wa5?Bcqu-Vmx7tq4c22!+z;l{1FqN$dbDx88=Y2g zP;Uh5j&}=|D+Nq9Wu*~sY30XSV@~P@`&S_Y7)4E4Vws_LMsMBm%8rnN{X2etepgj0$ZNgKAg~O4eVofgFxiS$m&bO{!$R zsxOXCwB)8_pLflk@Da^r6k%ZY6^`3Fr&3WN_`l;jml?&elu<>T%zc|Khj-wf_stTW zAfrc#JFbIR$LAoHo1Bae;%O{g_B5|#PIz(Xs^^?jnd@%ny4UH~?EOfJAyLlWFAI^H zMQAzDe~)h+VPRqYLgSG)m%e)a#zU{DP8lkcid(803d%V(3-f`98C93)wsVZbts49VI0MZR{QBCPxh97BeD6XT$ zf>Hx+Y$?j_Ax2U;dzr$Gm9&_EbAY|nq#_Crp}J=Y5pzVGn(Vbi0n+5or!J9v{Yp`} zs+2mqq9_jpH0jZb1jNk%{x3`lrXw zRe8sfY6>eJLNg{*ZbP$-`S=MJK&j+_!y#(ez$^zR4>$qL0hOUDpCSRk?>sIP^0xE1 zIP+-zKAfn$`u&E|C`$c)l#vZYn#Hdjb@ApH1h94l3vIr4%L)uym;Uolv|I(espNNkz8alP^Q~s+}J0M4~iaH3e_@ znf6YD-8p)8iVrwniEeAEZlfrAv->@F)ri5WM8-2rU`g=;GD#|hlxjQhJ$5%>H7b`( zfwWJ+B1w|&vAZEW9$t(o7bZH(q?MKtX)hAnG3Lz*oLpZGr^rZS*3!AQDxSDrv(qYt zF~ny)0oJ0sYt4{d{}sY!Dl*U2!My8jo}^K*AMtE#m<9%B29A!Alxqk5>_3FS=M-Np zc+y}f07St9(5yGp?l>Jl4`bBrj?4_T56rN?V`Pfnsc4rBYOmm~HoGg@3k#RdrVfCK zvkvRmJ0d#&dLN4LT8BHb`o4^Z?th}2hXgTdASu{b(QAesGs<`+!p6I@f(Sn6q2~fe zz=k3wT82#Prihh?HyWetF~#r!`b1F1Vah+uvz%E(P!FUq5VQ0l-kwR3?UZ$%kk#<# zXMTgTu1AsYI8y1J9Fp@RB-jka#(Z#+x9^H)dJ=W$C$1U>#3CpU z7Tq`uGXxf9B+Q+m_ZG*H%jF~|+17tifVeTycT~S2qlr1c!}&`@n%{glc^UaHT3`Mv zy8pLP58JN%7q-J&`EMJaEy#cKb1^Y76VUd>!RTK>9BeD`&lU&UMdDyvh=UzbxI>~{ z%P7%t#KBg1aj+@H!PeIm2Mz8*sn91YHvO_^=!rItExCCopJgn9em_}stG#D$K% zf=uj{N_E$XfU6EEePlnm-lN+vcsik72EfouSY80%E4lz)-o36YK!;GC-;oZBIe#zT z{gYqAjzr+QDBP3SIbtlEN<173l7+X-qcaRulCb2nbTsTG)n2+wH_G$k{9gMi{y+>f z@dtnJGJX|3wFDkh8qcK~swmjATy*vfzZblBzH0Ttp6V3bl%VDAld##^RVY48@b(qi znfuhlm{QU|1fn03TO_`QANLd({@_0D^H2vn!ysHF_bfsCp2jY^ahI3now6JN$w@{( zd&ie-e7-?8Ur;~USfL*?B}_`NSIq*{N18l58D_Xf^2@F-*tp8434GhNxdtC)`DONQ zI{6q62i1c;%@9OoXBSQn_3I$mW&goyA&eV?X{>Kt_#W0%IEUy57_am_`QhNCH8Uz5 zW_atqRf-4FLnQ8&K_&oOBK>@m)e7a_+8(fkNCe;RJ9d` z&wQ?Xqt!4MLeVK!H<}U3d7Wu>qZp-9V*uzaWOOjTNi0@sqpFd^DCVm_^|^TD-`I@e z{so`s+;JvAL(JHf8B72df!7*30>eifKkd*w$q+3{Dnc8#7+!au$c@uk->5enuxeGL zH9{t0|HG=h9sj|9@m4!q3t!WyUE<~yJQq@CICZzg9xh8=*%W#35l=vy)4fn#?_ZTv$f&0njX!TB0Xl@0w2?Gh&8XQh+aUZ4?JIHUE$y=S-iEFu78&d5 z?xVb>oi622UjM>ns=!lFjxpXihUtqRRxJ>?r`H15%dMw2H|}3e6I)!+XeRFg_@FyV z6G1z4j0)w4-Z9CL{X;!u-4^S=-cc7W=uTi%q+=%6aQ=g@;n;4^MoN3=eNmgrL&5Rn zV^uw*R#j!%j3YL~t+FapU>r$oqWl-t^2vMMMn~R_T6@ewOwHmtLNgDk!ME8plTSNy zVX9vzNxRh;G|nY4(3xqXs4zkC6)_)1YhX0!i`c~mJb6?K9W<`t6&|Fh#%qu9{=j64 zx7y)re6`0nUc3uAx$Y%bbQGv!25&pL`^UtLVQc#9O>_1RBwkMIO8RQbLD#|C##(0aAZye=~#5rnaH zDTXeT87htlTfgo#27^5ov@@?1d0My?uj%qw(djS_@&jG@PsVSTX4Q{FOz)luhD19H z3~d(u9*G`#0!fzIM$(8{gI0s&5{^@cR^-Yl#!GdGvnBF9k|g;?-yPtMS~zyG7-KPp zG&ge7o~+HV}askp26n2)czmb}Kh&)71xItO?}+FbZGf8TeKP7t;`U2*N- zJ!~t+e;u;3;l=Cu`7g;QArB}7-!~&;DDSCq>|+Ar&FmhsJnTY;OkJP(6e)7S(7yP6 zyA-T$e>|e{27OuRmY~xJJW8DZfZerz9m0mo=X;b@ePBIzedncRSJ^5$cb+@7VUgvV zq8JZ;`5-QF3Czk*RcC+%SPvf|Fgi5sIa-D~S0mU@kdguhbdSzH{VUZ|?3K1G+jh-Di%G)*y?RWpkA%my4rs6rW9d@ zk!tC6X(RMxG>hwYuOUtnOkd}EyLPRHnBD4^ZJ~#kJ+ZDyl~~A(7# z_W^|`YMIN7s^lI6=#&I(#y-AFNTc-;FVX#waE+M};m*1#U8L8WPp8Q^Pb=NWuGGjf z774yl_oY>sHi})esx|6*BPD$*so49rylN_3rS-7y?43&eAj}9##m*wJMjghwMO z$pLuKDIW>}_TjiYOCBm_Vde*bRgqJ65tJJN{>9SpZp`K3YdfOce!j}5$p4Fb-P4Vh zH+cVF&<->AKL@Sb`=7V-$zJQ66aEneuz5asU^sR6Kw9c21M@mzct)=MwZMADHIx`a z^07DU|0j1JesIJcWF;JY(529W?)hXo+fg?c)15^l;KlwY+7i%ld&~_$q=LdA4TSq0 z!>9=;p=tuci_zp9Hxvh{iHH{|g9Rbf4>Q$z-7#+S=Ly-+u%N`MNRkgK54K74p5m{(MjmqwXLH$qia}Y80ZscO3u^ zg}*a@60lZ;)}$8Vu3(O3_%`Hz-Q0s)K7nTND&*qdYKsed$(g$jaHu-H3j*VvdKh+C zQ0I>7+*jSMjGotg;D+hhyY944%NciC=i@jWlf=RFTNz2TLt!|V?`e$m>q_MZQjg*t zz4zGj;d%PG^22y?1wX#vFWzO;8AJh%fpAVIcW`_|x(6H*R3DNa;k&!oPm;TUV%VvX z7=BOjCv>IgO-4eQzC&XOukHf2I(?xhBETtz2k;^=UT|R@pTmnP*H!bgw8HtsGArOq z_?J+poKHDcU6F!ncd^j4;hQO}1nq-__gIETeDqQy|Xs98Esw2RCXMo-p zAit{^%Lsr!d53QC<`ca`r9{hR_qwLt-b~jM>#_ZlXyp+EK%^SFmLfLu^&F1~Uc%J@ zemuYYj*|q)fZq2B5huREGxBIN-VC~AohD)$Fr*+rLN6qW9v)^;@KxQ6OsSRxaTPCd zgcW!Jj*cm(l8i4&zlOGTX|PFaBvZoQ0mUh)#~6Dd9ulOqHkeL+PsUlwKbxd|fw$OVA_xV6UsSHC`idF`8_c-j0;zk2#o_D z6k7Zr$ho3VDWc3J2oksjpqIrsx#;3?MeZ5M?X)=SRmWd{AR`B%2A<9k04*PnN68qw z5%)-^zP9@*8ld3$CybXIO~w~He5t(t+>E5nK+VXcspSv1@8y(V-#k=KM9ezF)ZIUM7{&*WNg{aIWKZ!of6%M8fwBH`;t zjE7S3K$N(vXquYrucaxqSyQh;A5ABdS&g<6ipZmH$r!x|Yvc}#N9Q?o7%fDwsmz%1 z4VNVP<_H0D_3pN)@l8e}&l}y~KPd1jGQM*G1HN2;PU(5_QYt0&lm|=9D(bz7!P{=Bd zsa~|-qJShL+(pDw-ee1<(cmcXHCUA9I}j{)wX3U?d~xUtv`apNuj;WOS@ei+>NZ<) z-igc~$aMUhUhGIFm7R?1<&o$emlH&UC2CL5kqiW^9xPv4I1j&EiQ7%_+O z9SUeI6q4zTaPg!3{nJ!F`3WAKkC2i2s1Uk5Po}$Ssgvs%j2~ZVSonW~7DeP@RC`y* ziMUYLa3cnAJo@tDM;YCW?`Ta%D(}Vc>Yp?g7u}Q-N#96LprI9C@ga0eAHJTCCcXEu zE;X1Y$?r+rp9}GVaXpvu;2e(_J!n`Pa7$6)`g1>_!TfCQM_-_f6c`l4)c{$I_aL@) z*s}@V-`~&T9E`d%lSug!@41)c&@l?OQ^8#QKy8vP>rgL-d@(=Q0rP(1JY)kh=Lrkz zzWH(4i&evjT{6|Y)5@%aoimzWUWwj;2_?RfJ2C%?e&<5^91N%FEJo(xYDfGAcw4qq z2kU!R?}?f2alaa3zekeRJ#?8~)CM2>PA}O{@wRP$PeB>Cr`)Puk<+Y4@;a`GAp!B;2lcxI#x{P+5WSq{^ng|}ohl4IA^q9@?7??8grPh~cMd%_FCHe_2 z*6@Xvg<3lNou6&++=|;VJ%Ltq+>YwE%-JuG3mtu2P+jsNO;S7?I$h#CX5oRiOJvjZ z`GRyVe?&#~?^hzc$z4$^e zkBr``k*}&s&3wnRBnn7;b&1eZ~tGc-Ih4sc;{`a^F=9 zO^y&+O^j0V;@KuXdmb|HvM&4tq2zb|THaM%x<}?$^A8>Q$QRV|j+#(3Npwa(a6>S3 zL)%wxHi;1-)ClVGqeWO8H2Fe5y;P6&vpIjJAB^e2XRZYOQ7JG{X1X+8}$iQmSf7y6O$^qH(^^)=u%064E4K+fA|71LH>MgLhA3(E(qQZrPJrc*IXkxXf?7-d8M)-(c;JV7T#q6^~zIr&9FDv(;xWa z>Fi(l6C~jCqhZ0BT-cou#T1Lx$Q`kwTZjmR3RE0rrM|Ehh3!_yswUnR#x5(#B29`q>|kM6vRTK0&5})n#~v+PdM`a1c}`Nwh;wDXUs{=HQ=TpvAlH zXn^_kh_`Dh1dVcn%4COjBdQ?F4Tjge$Pdt5po0_yRw7WOewX5@-zC@Ge$pFWc1IK+ zq`?|ZuF^WoP{;yOF==M~2MT8%PsYjazUqZH?=Z|36UE`NA*DoZPC`*aI+@R|=9FZ? zM326{dlZVDkb^Q*M(xWKbB&@8sn2xi&pj%0eMb4I-|qyBvVD3|c#?*c3l4XMa083Y zC(|m=)MA6H3NV?dIy?nvCPlXhG633kTbntg!L-Y+Cg~7OwiHu- zkxUI7R3pX;n0-`Xu})|fmuslN%_GJuuwZ{5jwU;Bszo!U)cl(|e^Mlqy|~$o;3?nq z=?APR)bmSY)5q-Ywb1g4^rsDx{* zXn$0BFUS}WcyfP2ZN4NxchY3z4je*#PH&*Yt`eSDfD$JR$40>&V;tCi4B&p^gN@T! zH{#LLm(SG-vZFhe@jQ@~$DdoxMz2|KH@=vSLqQMIrrtHN=!d#_C1^M5@pdPyZzc43m<-cuw zbpA)7aPlO6wDV-;#w2F5w0QHgY$wQ(g6+)2!dCpD5guseTg*wY=zX#v!12(DaO{`L z4{1kO$zQS=nLLsG43!I>s8o^tOzMXvBPcWRa#j{+qlSF!snxuZC_5Oa*<{{($A5i% zhr3W!rNRWUKGgwO*y)#c-ViI=DU*7~$;^2vbAIH;;t-g;ER^WC?9W7*9s2V5D&4e{ zFfpIO%;x!Q(n^J5))75SMU~{nj7-mCQ%|hdZQ#%!`%|?4chgH0)q7W0>srg2 ztxWt+qfx)z|F`iet^dge3KeREcn(N$70hrqjd4SUT(N1Lt52Nwy!zE9sv_r&VQLJ@$ zXAcQP-OSGJ{T(#yzMG8t0w#jtwPj@iboc)MH{OB10lM+d5F8l>7|7UwwC|XGq#ABM z6L%GSZLYul$WPJw&oi>x_TyDffeX%mL8I=j{~?sSUH`Z7`By#vmCa$(OT)$KCoGX2 zVTFERPR_m1lXMTBZu;PLgGVTlE(myByyxyJ#U`%{7oXpeFCv_jE zMk4KZWQc~2M}n%|Q92QbcbBq&SO2alQ#We<-Mmq=tdSf&a=D3Iq**!__wjY@Ecf<^ z%benzpDeKndJaQxIWr(YI0Fswm`YZ_Vq<$t8r$2q#`b>!WBZEsb&pZ~PE#lcPg;)~LDcAI&@#+63mDjU{C+(7 zhXB&zCjNJ z)GpDUhl%iDNMRTF|Ji%fu2hyTLAbxx`4z6GKfGPbx*ze2qQsd&H~a$<(Rp3GPf?a=a{D4$;UC<0C&=*{4uUd3199CY-W4bu z4r&u^3{C&=um7N5aWtZTgvnxm1h=BBaoH?eR(LmxmJBal5)}U;56r*FgYqwO=LeZy z(N!PTBoBf=jSbOr0D-N zQ=$Je^gr_7cYGu(0Um8+9$1Y_qml1Aj_-oe8aVZi4JxPILFKge@d1_&@LeDH?J5|; zLfz`6y=XV}jqhul!k|%UPY$c?!CT?vp*$RP!)Kj>cHw@!y`SC>hy9ZM(sU2I^`Tq8 zD!QH1heJ>uG|%o%XRCHY2dy$V_t)TN(EQjGS`GWX@G;hh01Ucq0D6m)$9H4#bpLvP zUHHd8|DQjb#@3(I^&fwcEHjSe^{?xORh0EV&$oOEg#$FqC_UK-4)4c-Kc0_Y z1Gzn5QvZW92d(blRQcBll(D&|aq|O~`qAl~ANN2TDT!-twFQ4xrE8bM3j*lh`NyGl zo438n!01iQg9E#$TW0XO?G75}wb0E4-G0?96e*Bf>+h^vwHLRyff$k*g?VD z=McxR6aK=#oBgw4tA!tVVdZ8WV&duul%da{H*`acR`BFM|IKanU8zoWaNZ9KmGBeD z5_Vd(VffI-56{jo@q+`ef}b7tTrhBZA_~$gkpT<(rsvlAUWHv6*ouP({Ywxw8a+86 zy-n#0o{pBmL+gML7(5NrQsQ?AOz_1PdL38CWj*^SY#BJK39oVEn)Q=*hjcHG`QX5a z?PXoVeGsYDsWaT_V4^2DT!O}Rmsy2?pt}t{7SWwFC4nd0+@C-v3 z0?#nnlHwM0(pszpW868vH2#UbfeYlQs2jK&`>kfxy$W7)@*TIF@lumtl7WEBflRhY z5x5#MlwyWF-Zd0gBnvBZEjZ7LVV~=FNU7ij_;0=@1LBeacN`k47v)5uk?pduL_OXe&88y_{0V*rRmynjk zcAz~oT!5xYM(6B&K$oPMFg-XRGJJ{|?}ZQ~w;kqyL=KN;2Y-VTwsS822u~vhLQx-7 zt8Qn2e>Bgkauv@k5=`!;>Mi`^PPhJG7%f8%Iy8q!0ngI#Q#c{2_>qnup#^}Of_MD9 z9TPi3af3Zt@*7tJ^c#J7vL{saEQ_MG!mY#Tg!Pjq7-ZQ6RT_Q~F6qW;zj=I?0Z2GN zrX|l(ZfJQvs(IFGp1D=fYSo(6K^k~cGXSFt$9{%d2VPM>(&PBCYyb>#hs##Uq?;Dy zx3W~kA%M8Cq*I6{w@rhA51-3Mv*nVbl^umSz%ah34|%(O?&@CA#!IMnj`x?mjX<0p z>A%c%13wiCpjCs!ZvlW~6F5e28yE+RN3tt&2kVxQ#09}i3cHcUv7I~gQ^>iLxKnj2 zs?h)Vr4a1N5urn|k?ht7c(30L$Zi9|`cdS%^Q^mo!62zugXIg4xE{EKLI-VVC@nH< z{Mo(DRG^dxJbwPJBpfs5Cg9mg*oXLSQzf0mFdGCuW&Tv0MmgN+m3&6ofPW_8UR7L1 zxk$Hs%43wv1S{q+$~I-NgYFJ`E2L1RUf>yVPZQ4}PbbtciJl5sBzlkvXv$fP@z80E z$5oT{97G^ydIwz60WEM=bs0tIQ*ZYA1DB?xHtJE&gNntdA#EKsdo^`CDCPNiEt zT-V0hP1msjEW6Z>opsY`0;_}SSHUAVy#vEz_r_XxZ>|rkS68!cp;`5-laJ>3q7G2m zMGKX!0S$ol+6Tb?a9W{p=o*0Dx$bIb?TJ>f(Yr?*G*%Z)RL_A-J*-!EhM;!)zM8GU z1UL|7AN1Wd=&gRXDlaFC8|$*O2EZ_8MGIW{)h?(WTbkqh_4e#guNlpz^Ko8Vbt_W< zF5a3}`=Qm?v|5h+dEy`aU9C|0?LS8D4Ipj(mrAnzrw9xFS^wYhk=B27w7CtSS_3Xz zW^nQK1_jXRKe~m!Z!i58=%U5htO36c*V@nl@6A)-w>pkLLW`^kmr|`(1)%)_?1KN< zJTCRyjl=O_we4tUqgJDITm=`$;H5j5`oK9p9(sNS@lV!?Up zo@tNQ9lK(?*R`Om)^@>5+Zp=vy6t|Bn_vi<;|IgkT9fWm`@I63`|ewP>3*EtZ@Nx_ zH&++@2lw^;7AO+1is}H)buOEwU|J;3Oezps6PYKM?cK-vu2krUl;@rh1>;W=i zPY*#gwSmnA=vEr5_r>Mmef#Ha3DlgA!}V#eeSRvLzaM(wCBWALpxi1Hx&WEL_q@@h zuKzHy?=J2isqsI|qP+f%(jWhi@A*jUKOAj-&7Z8{nz!tPHQ#E$HD3kq?!yT@Y(Kl# z4Y*KV{Miz(eRKd1FM~tg51w`1pziuCILv(;l)7-4v}=ctVBPFIyWpl<8{LAzvfpWd z)^Y!8-SNQ+F3V4Q>fbx(7qheB+rp}}{l-wcYFOJug3+ z6W}%{{=+*swU;Mu)p|C-N&R6BuAANR{AZ_M0LNDCxayu4je${EJBOfq0{4z)8vtyShI?xj_G<^!{Q&MJU~cXjKEm~QgPt94*5GopIjnWM z`ue?aSUs=0Zn1W2^wz##a|`xE%XJ2=g4Mn|^qYeZW6=-buTfiP>j1~1dk_1+_HzdA z-=5bSNb67=f`MPHY4t8d2K#mJc=rCY^>Xgk8pGyf>6VA>YWbq=*xj3|4F?;Q86Kas znzt_(?LlKusE~S{cjxwH(4K&%RjYkmH-YOktJmOsFmPbMFE^*_b-nZPatBMm@(&Al zK84%!%U!1c=fyf`cjE(~cHcLBFlhjP)P6Vx?PcMkU^}0i+Y=3r*IB3QYM+Hc!2;lC z+aFc{=zn|`S_Rb31>|k(OJ{Uj9XC6VPP>0xa|+$_+mgF^JUhHY{nos0H!7g`z8Ew< zUfxatcM`yaT~v)hLUc)TF~chsCeOy`gXhDX7=0o(~XZc6Ki z`yu2)Plm2L&~9hFL37f3gG2t2p|_PD zGQs|4UG3fe>}U>XOu=2fH$=x-|FY`Vf4<)xU*1n%tEX1?wg@h|-Mjb4uKm)2y>j_@ z(HOcXBY*gbnd=Iuos=&IR&4|HUj1ra9ky%Hd0ibkFMelG`)J&D&e{#XTK#liYhYM7 zebzR%p$?H&Fu6b7A7a01Ux@InzEL&VM6i5-J@bGxoZ-gTcq?FKa8!!!5N zFnz7*EcA~?6Tn3RrGjoaSm1BVpnvfv_58nwTW)aE1j~f)Ms5eN6#uVMH2#NGHvioJ z{+7?q{$H{4V+#i`(V0uv%Vn#?`)obGE=J?!GV~DJ!ENjB=3`Q_;!6o(x9ClPG#`_= zTGT}Z5!P=s>x2K96TmG>G4unQ4VGGx3q>*v_Jo0Kx&0VVk`!3P6(x@^OBzT+vi;@- zkip+2l?0nW*=CAxP&`x5WxvY6d@ zs5;6#9C73+(OF13inmpK3r!RZ|Io9Hqf+RYfqH0o?1tVD$lnur=LN13-$$dT>qYdB z=$QB|s3)lEzmvtlug_&Ubd>4DOh;uW=O;#Jlw2##TWe1=cvd;aQwA9^%PMc7wAq%C zh&0clJ)!Z68f}gpwupEkK$ia zr+X&noAsCIRkb&i)1$w_z8jtmnl0vubbjIX@K?R`MX1C7c_rgWC(ePWPn&QDK69^# zyP>cTtDfz93?N|>$scRa&?$W8hVnJ^f5`#}&`cl}&Jl(=fbA87=p@FwiR~YaryJ=|;%Rm zip%>T*ei#tqCa%@N-Oo^+7FRsdghzNE7w#B8?pRnEZ`W?p==AHL*E@F_fHH04yNiX zhNlqzwp%-R(uHQ&MbZr1ke=IaH_!HR0B4{DZn`D(kB$B*qkqT+w+uT{zPA2<+=hgl zU^OPx>+BY(;*|KLa`s-*q*P|A+IJ>WF9@b{fEq027& zS=x4eO(L6?ilGQDZ{aI8CViZK=H)_~m95CoZ&}%hESp+I%fdEfJQ0W(-%?IHCKn-RVK4XuE!~>Sv_5;ffn9- zrV0NHHEa$5rz4@Sg^@{A7#j!6|Mi#t&#*tPswyr{4N}dh8Ci9_YM`D885FauZm>{t zLJv2#kt<97koH3Sn_Xr%6fpymAd$<&-? zDl~z)kI)2WhR_80E|A9Ds*kUwxipJfDPb}|QMOG(sF9p>& z>wsh%z%uJD*L1OwS$R#js42Q5P-;gqGXp|5EeU9DYyvp`V@&c7`$W%QEHmiA}sCm<^Jyo z?psszQfNb{jq&E=brkR0eDXRTe~vwLCui}t@@^ONw`HJ5QQ9mU9}gzKe};GKIjfh#DuN94Ud`>!{5V(Y?3!TU_2!SiCd zdS1-O9*w6iw&&^jZ3PKktZrt}zFfV2MCS^M^8PkjsR6z{!x4quHbRLBy!U0`3?|eb z&t^eZC2#y9M5q*J!xTmGh9Z$zHwaHc#)f}$GoLTs=A&^iC6t7{zRf+jI3HJwVEWpn zB4nTWZVxFYbwjG{vRyO;*J&25ehFzr!)KU9OIMbeue{kb2;HZfS_N+1Tp`l&;p#zW zGwyr3#M4hfT|5P&o=u*me(05ApELQXRYTiPUwr53nnJ!3UVFMhityY&%08+36SU|=OEk^mawOncp4tSRq?bWgE+k--_S%8Ihk!Bkl3DK+#SlG@g*_<44-09 zoC-Q87_UrevDCD%vJo%@z86u1X9R!)no5$cx^h^91A!~2V#TOJA(a}2)MdR&SR6xU zb2g?p4l>GduEIcLC56Dc>XyX1VrgAuUHJo7J#WS3I#w+sBa2Pwi~wG3;^+9>)pHptPUatD#6zXA{YeFqjKIVu{uW72bw&0z*8t$I3ny!^; z?-c6F=m`!EETr5j zRgl6fvPh-!$hgFc$L$M=mEcZ=Hw9!~Fhj?}81K_CZo5!B0^35fka}fCcRUgdP}mcB zT}etuLFw^nJYV6SvMtND^sh<-e}sauAv8D;VEOl+lqXj(@x2Q$`0%?-PGH091Boq(eUm2ICuD8mfq!g&t;tHwG{v@D0AHcQ|C7rs+76^p`o|6IOmz7k` zpqyYa2o)S3$a0C~Cpv91gk7WrqOf=5sm^#-oOD*< z!nO;zpqr4|@vGo+332z`6)GGo-7d9N5ys;SaUm~qE=SteH;rc9iQl^Sj4nJWBp1#v zM+*Nc)IGE#`iFigZkFZzy9SlH+sR&7dZ|(=YMO4@s!i}~X+be`7=Dr0`vnBRpOGvO z-$VvJhAr;y%J-qC1)EE^TeM za3YmRI;Y=$7L}4`QAs~4{U)WJ zL7JPu6o8BmMe%a>*EK$;dlc_yg$Ahj#RIg3Qxs_yp|Lh>e_oja_oO zDn!9ABAxY}S2ktaF9|O7yU`jN1%{p9k~oP>T?!ZdyHV?5+qS|6@>>xZaqN@XfZvJQ zaxC-k+fYeZ4jsw~y1_FY@E7Jf@B``0lK2lJng1x;*x4gH|M7eE5fYn?h#>WyG;&*u z!aG)^me`4ZH!{PnEaRhbPkkwL!wz)P#tH}d8M(Rtn^5W5`u?|-JrPHD6D@u>N!UZo z;|L( zFymdFe(?;7z++pJoz=za7dHWx<069XONQ7NQOaOtzYB4)YuT@-OW|+#i;40o8b{b) zyRM}*69k1QTe4}PiAhF9yu}Bntmht{%dj6R*K7}rX5*-CzcwC zqOf2-%05*7(g_=~9FuCITUW{;PZqO|ZH2YQ@O?KcpDvSQM% zDCO-69#T#s7|Tj1Q1}ym9eRkB#TKyR+fB;vh?a9nB8ZckyCgQzHo^N-m|mox$;BMv2@o6r!0Z3YL|gy?lxA_5+RV z72%+0S%GgOrZzE1ramp~8rS(vTscTM{#N zO5q9FhxXd3NI7kXJT1vIfT_v5cKPrRG8QiWhsb;Ef{Jg2 zCU9Nsp_y}2$}kda)3e05h$#pnQ)a^Bq);Y0Vjmo8P9!M|Y-uM3R-`3D zNg8)+d=GbtB0#TW0=o-LT>?C5sqsJFm{B3y0DZf}XsD;o5IaWE+}vxvL5 zFCU}6Z37K!TP}VJj9*9MB7%IhgN-5L@Z#&_FUnw{vB+5i=J@>Z3&Np5U8KA4`xAeVw z1opS^lChHznxyG^_=kh-W|E7y;RJ;6i~VEWlg9CI$v@R@)AQq15sm$Z??= z+@#qqv`XHqB2_&cyg#zO;S2QyAt47?!D2)ubu){mtBz*bLfPW5g&dnw5f#A~(@^Sn zNMRX>S31I~zd#{Ub6e>Vq$LoOC5<61Mkb0aPjnsfHY^rYTB2iMdiIf~+B(#z6*9XF zFG#WwdKAb4nHr`_?+^i6qOtO_0p;Qt$H6poRyZoDD@vnu*ZFIBMll~zq>@*(XpFM7 zM$0=qS!xq0_@t~P%L+%-*Rn(x{9`VyTo`*Xh`kCu z^0XAgr0JoP8CFrz&=67``bF4)$WX`CBAc!>nc?F^nh5`?C`atPl59%f<8Ff$Nl84? zkrKt|7>i}_=$dh(t0>Lg6QK);7K2#v&K~g15u_9&w{@^~L*Xg40CM5t3Nc=fmWnyP z!t8l>Jexu}l~8kcx0EvUDrJ)!vLpoYMwsAffTAZb??9ZZHtY|g%Ao$fxdG5n$9zuA zoKUDGPjcO$V8rrq91I1+xg=);;T4U{RSECT-T1!?o~laYl0} za`4S?M~}{m)coI4I8i?5^A^yPxxZb3D;P#)66`HuhbDz67qc(WB)QJ{UV4M@iIh>< z9Ul9InQ^yE^Aqk4oaE5iSMwF&0e6E*_DV5+t2$kJ3QYOZE!n5G0Yf;x^zRNFIek=-3%UQQH^M5R|kQ_dzHpTx#Ujt+74F1i`WW zP!Pwq1ZQyFM>Hyw^&pg&u*w0cp|TTCQN*wxMe~SWnh-BsXNS(vl|Tz#e& z+Qn!F{JG9}3dQw!5h7E!KZnp!K!~FfWrfhK`KR%6dE<}0+ndp&QqoK7N8Xf`I7YJh zDyeYPWR(os&RIiTki@`cQg_7Qw{$m10goDJnCXeAMhz(|dZJrP5@-T(6zAiTt+L88 zw3mr*l((7rLM`~y-hJweAceV)z{7tldzkxiU5mV`i37qiwU%Tm6AbzBb>m%TV(Z{s z^K$OgNMial0K_^K<9wi~jw@o$$Bcw7Nv}$h`N|?&_*PMmc~+EUZ1I&mvn(l$)kR@B zWzdw^;x_5>YI3;>-A1wbz|w8YHnnn5%smzdz|xOcjUUnFm#JQmP!?O-t!=9#f3+iQ zs%BDs?)p@6=48uUKuUCZS-kXtXH`%r9z=;}b5tXp2B56Ot|XNMQpVshTDHW~D%z@b zDOKW%hdmTl(zP<};n*4_Lxmu=`6a5%C6GB#cvzV_#4DA=RpOP(qzpd^v6lhazx%L! z4_vnU$AlZcnXDi$JX+k1y|-t`Ro_Kf;uL;Zbr9;NZfcfcl#{anE}oBA$*}oWNh=z~ zijf@cRj7y}0I_kQS~i3KZW{nNJ?n>l*u?Go}!^waX1*k$YdQ6 zWvh92G|!56@lq7$m{ln@RkRdenDgF=FYl3*sL^;i4esMjP?NJBBPUwxSl`rB^CWD zmxJFhd%?U{5=s-F;FzveQo;FpeQ*CNsVS+JCM!v|Jgy3M$RNybNw+JIABMsRjk}*m5kHa(lo7XYL#L! z$27LABUUf-G#*WSkGtqajsXIxqGzNagcA}{I%3sx62dfTx}4Q1wW4meY$0Q&i?%V36gaX|w$h&>S^p7mxg!c><%hmH@KIX1p zNCIQG^F1*-*}FN)|R}2lIm`&fQ7uX6`M!Kg)%i$NHs? z3#e?*l@w4%Kt?bhkl-l8v+DU-Kc>(I<=Z-HTNo^WG*5xsT91P2%eM< zl9vz^oK-%hhSY=YVJoE;xvl`|DjoFTP}c|lGqnm?gpwUWF+e1E6Rpy2o+Xz}20fGM z!NrLSk)j+fL2etxO*hPf(EXE$);ye`%nGj6&=49ISc7De;1XWIvBBTqGkyWmH#k+z z4?GmAAQij7MT&l`BvmNd_k+O}l}vj9id8pyG#bWkwCd(pg7yrQiqydO$>cZ{zbobF z0ZlLy!r*?&ZU^eXzh6jzXP8)t*albMgj8_|enU&=_)I->FC#7%UyJr&iM+J~ljMGXo`@cU8ZS;e#v;=hV46msAU+>21$x17|XyM$+}@vx4GYsUawdY zI#&^;^*f1`wgWz`YcLZk{Qgg3sQhMxmRPn0be~96f&X5#k}1NG%-;TnCVx2m zj{WITZScNzBYPu}gfb=zUe}@_^?xCyft1DNomQ#L(1++2e-o04`|~e9P}Q^{A8c{w z{H+GuD{I1>{KcGJNF^aKJSI5`fAtP2lIN9;--HdQI075D~Oie z1HPMxa8SH2c))n z!T0d5Og(90V1#AhzkIG2)rbjY;a>%Pt7z)v3w!DnL4;FnvUV#ygT5B6nTO2x4!+fmlG?0ASLp_vHcIMNjEqM=X51Sd=> zBK=o(6aG`%7Gk9U_9DJ#LR$Hb!9#e2F5S^6l>wV)*g@D0CQa?)agwun!j;th;|t4h zypp)9?jI`?zk+i6vo2=E=;``iZFITt!dVpjQ~uhil%dIAGp8iPfmV?zP9%ks;w>YLxn-jz_ex}G5|}(e0CXOSFk)cpLvs0fyQfE0zV}J zUaIyvKTKqkw=-#!a=<3fNnMQVSjum@8xBvm$kmE0l5hU5IY4|s=&%snLorgF7P8Hj z8R;O3M|D3*xCpx|O8H8NkhWmI7`Sh&1Vww?gL}2R-A)^i5>5qX(A{=2Wa%|>K{E1S z+l@L71-bOJ)82pZM4?7lK}A5y;LJ(q1oI+JH(Vv;6W=lE%y-(; zq7dN}7J?q_qXW3P%73-8Fo6Pb5rh$(;^?n$wLoOL77*51WMD?E67^2feV=>kc9VH{yxtqmt zU~nn)KR&sG(j+1kNB@+=?=eZK6B-@IJWHL5Sxk5u)`sm|HL^~AR0GfVI5{a=-qW#n zU$StcCM{l;QJ2TNWEEtbh9wf7HJ*W%>crox&Q|eY%3ZbA687=<>cXXL^nE>^`uD30 z*Uh$odGNj*uf7cM!Q^%EIiAPKbft{DPzZ&gl~}kCWr$F5+k9W3J>51b{8%|}Yr+Hg zbQgrZ6{|wr9tEzHq`eHbJd?{3mU?^dYsiV*+|zAaadj`Vk@SnGe7~7dg!3`Z#0B{}WyN(XIqgp`m%G3p45JMw*WcqI58`beQn zzLg5jgqC{I=j#Xw-wWi#xmSE05v$j?v8-^jLUqU9=PARL+A9jO`a`vY_jl04_f0lo z>Ki+zq#d-rWF_Sw%QJND_MHB!dkK-FQtH;47r&0Eup;ZFN@%^`YMEgocAHA9SNeUlrM-c`ijp5F{v^z=6H^QuFwqaLHJGi)V$l z+#kM_K7}jKwru0~^dpK!T>M=}8~rXH=`^aG6r}byqLk}T+x)$|lk*>?CZmL#tG}9F zlmMPxz>JTl@N4Nbm{~93j_vo-XjprbQT9t3xs%0Hm~?;jo4bt@?Vzyz8}*xtL@qJc zuO#h#I-e|lyTdu4>bE_T#Xd{D{=Rq8I8wp_oElOh?ORu8gf5X9m3IfdC}40;WBn_> zpJJwg;4dq)J7V09qX)8z&1Es)k^J!Atn`OVW{T}q2Fk8b;$&Yw|M~aQMU0H-!@^#F zI}NB$1l=DOqjG;-)RuJdYHPFn6=&K|LzaCXB5fl zjBZGXyAOI&79P+brJOUiC6~zVJDbIVM7Qc9adF%)WVIu8iIAPD(P!M}Z9J&bt8*X&P^vV$?_Nzu6Ta;*=-hBY2*{7MzybrMKF4UJJU>EJb5tV%138Uts zuzVNhNPs^%6;c>cg1N)~GQxzHNw>Ow8HJvyh|sKGlV6xX)cHnFyMf7|BvO^~F% zooI6U0vS3jnL{=0 zJcG1X;*fa9DHL(U2>Qwh+z7*;Wg`C51A$KQ0CW2u7OPVikDo8`d){7=6;$;OI($ixz z2VGtj?x$|jKc-N=TZ+WdCdSSXp1+UTA87N&Sa@y{_Q5;;B zBU(;Aa!9Tpgr=y{i!-mw?+-kSm~tiks(f;ACHn)VUaY7o-+RSKfF}3|zM-Z2t!5QR zdm&lWxokBgYx=>#$l@BE%B>WO(m}YN!Scr|7TGMwNWcGi97J(okq%f`1aYKy#}ihX zEU;i&3JKK?zyJzaD!fqMiF%ggC>`clUBx zgMT{d>3*$$+U(Suy)R!l1ie99&8gbH6z9`TG@vFDqC_9-uciW3QBgv!&VGH*<6}@K zT%Pe=c=0z{=$lRlhTkiP+85pa=Cu}}hJSEp3snm|Gx?3UY1%1vmF3$AuyrbCeea4R z6yRT&4(_JR_jQ5!OHku9Fp^7SF4PFl78@Nwt(UfI@fK)399JH-w!CF)aRV}QXF(^I zcWP-~ly-%-lJ{o5TSmo!9WV;?6P%p4@}ALo6`ebqc5f7e9AXNw5-g&Ky&nu-#UN(8 z>YiyQcMu|u4*P=-$uB0lJnR)!DZ*&)6@0iJg-AyGMS=7dQ=eV#3inrmqxu?b;R8V) zTq2p9sZ`*5Z?*8kI#jnpwW1ZawnC5ay^wiF?Dlk7?GgC%%@RAR5j@OZ^Hpe2BAO!Y zG^{(u{w!MYOEA(^-T?hZb@;W&P>v+(TVQdfq+A#Uw?3^D#gxSL?-vt%T8?OC_K$*t z_O*?XWQG01XBn$Fo^;=6batp$q$R|a+X4&E4-qVKJ9fhW!J3qKV|U_d&zBfz{({`D zaCOG%7c)>B{)_`kT)PQWj$hgmA_P^U`>82!IPvgE{ksr^03Vaae8qCXDl1s3d;o&P zQkZGlnheIwi+&mD^#e2%0=qPpv9h6a<01H!n}*D1M(Z-T!h$!9BQs=!#S2>z7_3%A zDH2x@fwy9W1g@04FmN4_HFA2%z`()lfCwX|IZdTcOEQ!BU;vCyVZZad0HM| zzz`<>c7LI zfjMyQl>5ur3I#^+m!7?=xz3&59sL#V4nr}4$oYla%fdn=ffh%x6y*}m+$$xgkdb?c z#|`-ew1x;eiR}BB32KP8`V$ z??A=P#-D=O;d)$rmMz9Hrq#mT?|hR2L*qe-sob-I3!a7m1Z+b}@fjj+fF1*>Muvu1Laq94b@DwXkPoH&2VV`HF8?MTplOgD$ML zZR4U?Nq&GYLC3ewAbR+G8%h#7h=yQ{v`fuN?uv&)5W`mP+!ErW$oApl_L~R+szQiX zv4D&7u-GRauWU&TDs6FOE)&s&oU4F{H*o9;3vps(E!pPq7jW?4LpKot2dC}b9X|0x z#Gr}Bcsszzvy1~S(47AikYU@q6AFPSR_*r05g*3zqZZc^xn>AJJjoISwPZlHCUp;g zW>KzQnyO~#cuOLzCgKZ`$gIAt^8#BgkxhWafnb{5?A1B`TNM}AjEH`Uh*UvOWf%YA z@yAM_CddCV$$1xa6j>&zNgg}0HEy|U1vA2m*S#mz3~h2bg*AwfsM1-Snq1V9XbgFU zgDFu*ZK)d2wi2s7yF_!~a`_%|RF5AVULP8%DcUWz*6zv5&gE+HIu=cVl7TVs>kK1; zjc2oNg47xRlu(FyHgU5kuB>NBGbRZ$r`L&Esm$m= zCc|Q9TtX8>i=%@6q72O|#-n61I3<^ihv?Baox>A;hHe9YTbwq_f`3J%T!MdP_-CU# ztn{8L3m6>yED9UBDsF-l0wQu5Sgt@cWGS{tA@*P#7?q9)(ZpOaf?~3G&lh3KF1Rd< zYXq4QSzv~!=R{0(3SN5d>1Dxzf|&cF>biK?)R33Z$&o6!XRVapuEg}V8eYlD*d0hh zG4!JncGZa9NQ2^=6#JN9V$R%YlkB0qc=blM@pkyy7YI0+4P}JZhL@7`^ zJ&Az|Xb^j8+hR^Xo!zBNr?$1_Tktf zJF@6|H&JCIB#XT&AEg$RWrZo3wRUwp32j_vMX;0a<_!{nq!#@fri#ezDv<=0 z1|CJ9mfPL63v@0Aq)t7-c87Yvo==$%#@Rjyru-WEfU}%l9Z`r}KD=FL{sGt49eub2 zNMRuFK+j|dHXLbdig;c`aSCwR#G1`i`+0uwZ%8Y8=RLnpKLzC|^IeDsuhJY)93k#F z@S;g3H(Z|35*J9oJ%uq^)BFHEnt>3RGKE&4UKKMSs1{OwCWfHg#oL+F>v1%f z1eHlt(Mp6g(rI3BcOdA?oB4e4HXn_>`FPE7=b3avWV2;_aEd7CS=ofW`FOMPRJuMM z7Ku+Dr%~M-4W8<;ZKxdS8Jghf@d3Jtswqy_5cKrom0b#MU&GBdB4YBzXuS5G zd)aFaTqskeR(bmH)+6*U#S^RS>R*0XHDLJlY;FG^a=yrPjO2}(LRbEmx+K?rx_#GD|h zKy00Q>}=i5ELt-?sZ8Zb#iBYZfW&NUTr9i{V8RE?xLF&vBW=o2J-GCG6=4Zw2siR= zayi_qVu8oPVEL_LkJ;q9$n_a}Yn-{4D#j&CeHuVkX|~A<0si5e>7o=W`8+9cC?PY% z0uCB`HiH2_cuTrR&F({Rm_bp8q%PTtwdWppyeTvCltb=bdDXp4Z7Z*D zb8j^rJ+2m`$B0NfU3%!bu#zcI8u!JJHyyl%Fso51&gL)s1jJuXzT^8i)9N%%wN8()Dp)s2ZEEt*g;!Ri$TO;D1V-U)Gz zF;XuSV|pR@UlzL}7DdJSlHE_LVan4oRMv!8NYBKDZ4f4~E>2)Pp*!+q6~xf6vl6DH zXQ`&4#C_0i6XK#2WBuZAc}6O+y71D9S7f~({PTSC3YYlw8IHmdj$zc_j1F>`7dp~I za)HR2j}|Z^eHbYd?NoIUbuY)1^%VSm0_LcGLmCU_qnHLN-qB0ZeP(#|+b9O^CfLn` zI%!DyR#A5ufrc|!1VyFv;c;aH*C&$kJH_`2Ryml!olp+*0H5P7MD|8SdQ+mGgX4B>BS1)ooCWyLSh#IDG7IHphnMWSV-ing9qTH>f9a@Sl zje2DyP8)uf2y~Ds5$Y)dg)5#yHMc63AbNAzpTXe$8Kf!5S7y`Cu(^cuWCC`2?gbI` zGPx))*lNFn$a{q|K^%;Tc8n`1nf>|sFO>=%I*YWZJRG!~$;`b-yCX(!mI_PdJD}N9 z!!(4p@LtZOXwWIh=V?ZZqO14=w%4kF(U1gD&sGdo#l$nXxGcb8@wcn!ibxd zFu_PEys9EImugUnE@4J?l+ohp`3wJ8NB?9@ZTqFKx#kB7H9>cwhoRIvx zQG^*5Y9ggQ315z>%u(CWsmh-YhESd3@1&)wD27%d-2mW|I zeubjL9ST(WbnqW+IxJUraH{<4Wb_}xQ^ov%C4Ru26zu?LD}{_j3vH|iujA1>lt^Gl z&x2(yz8G)l3!z|CPciqNmcCLR6aXbvtcZJI_y(RQM@1|=w`zg9CCmr3oci+{cu;CqO#T|(a?p^|}TFT#1!IPEu&&oThP_ZBR<4?wl*b_P`D(Ac1H)um}e=5@d4 z*86E?3G2!jiTJ`)>>$%IuILloidgwp4HA-G9?4oGQDsNRKCuDipg!Su;Uw>Y%Xa^m z=T1}FL>C5eAmPUbyV+B1v-l2s&kGT|gc3!%h-pY*Rd{X(p z`>B7Au3PND0jBVOrIJ;a`9DiH|L}j`@!6UGQ_qi`IY7IpTW0XO?G75}wF7d*|CeVC zy-LPXP*%@Ua`|?PCH?8$0q+JB;X#Sh(sm%2L!%zUGO3`!dJG5;nm{AhOLBlA3K6p? z+Lw}8>?CNCn?;VgcR7bgLTv92z%yw+<3t`l9*V%LkRPNp&t}|7d<4s`PxYP7tsZyTYobYjI zuVR@bz74g<&228C=It_wT{Z-5143ad+JTbH!lN421cDkdi&MI=8xKYlgR=<2DX=^p zvbSD^-F~DB{cQo3*tIBXDasEExp8qacti?U-QZ$=^||rI+PLyA9oY<)x4u^r+>mot z4>^O}L--@D$rMfGh*qdKqDO8?%F&flm^#j>6(G?n*?y=TfIMdXn6nEKgekR<6jQ`u^N{~Bj2sIfeV1K0H8N0fKLC>E%beR>9;_)=`=yJ z2K;)n3Lf2cr|ECj)pP%|cH23x)~aWt>t^TC0e9_&@wuL^0T?VU&hE#Z?)h!0@iDKA zS_N&|J?zy!7NDa!)mjmB8-q^4e|WjCKu%@;aedLA`)*CEJssY=)w5wAK-l2r?W$G# zxPEn==Z+69YSY0*V^KWajNa>h*PXAH_C=%mIxN0II`rWosH{((ii4L{Y4hZOlG~Vd z?`HP#^sVXoAD8zJ)6qS`F@rd6OYX<8R~@$N?dsc|<+Z?f(k@?gC%|u=RsCfZ^ucWdpuSw60pIoA`!;%ZUR%Rw4(I{UZa0DJG^@4)pHD#7 z^-oZFr+b0QA3Kle`6YT@Ujysm{;Cf^<6}{2H!jac4jKao{?%J>f!81WOVjBCzd3?q zQnjD1EKq;mfK@=#dt(jpI14aX-`_sF8>{NPJq~Ikzy{*!71_effD} zH5yk<+jl-Uw;E_a0dP}quHP5d&DHvR(7d}leFBYvQ|VR@*T5;&>g$g-oJR`>RNV7( zciw1ztij-8eRuu2u3vv{uB&Jqy0DL7d+r)OY-4r!1bXM?^3U4~@Gz>+Z#&Hf?3aEO z+ymzU)}OQ-ds(P}8YJKm)tffg_2ROpYt433-}wGv*LAe@xC-tDZh6?b9)37h1r*;G zlhcX5elJ`-G>UHL)PMCGa0=GnX7}LXYJIi=V>lfz9^iC4egxOmF6i8pZ~Su~lt8Tn z=X?p=H*CLIv;8x@I4JnFVgt7AeBAok2B3ap{k+gzpkMwp7UK;7$Ikj;`dABzdKfr` zt_$bbC0Ps4cW^D}y?U?n*tK77-iFiaX6T<+>Zk6*?c4Q7`yuF)`6)nce|!NKm*&aE zYJNZc*{yf-74r{%m_$A#5$boo?TDOLwJ*73k_i;t*zpbh-f zY4zoB+Bm8Hyx;V@PuHX2F8DmTfPJ&R?gIDhWpLYZdJ{CqVc(gf)_E1&ytdJJ`M~*H_0DQ=9<>|VXF+p1 zU03TK9sT2<|IZ)O#IB#z^Z#|cT)j?FghfHan}-odIsdhisY&O5QPcjM|KIYF&i}}0 z^Nc{P3mJi~pU4O}VCWpapN5D3S$m>w3RZJ-TDG4$!6I%{ItA^by?J{-y$3~W(|%}K z;B?UZ*c4g?d%n6jcWZ~;`p|V-Xjh&df-0~J{%7;J)NeNque7sKs{t8=_w$p@VXf0e zJGgVwhNsiZ`3y1|Iy`V67Q^*$0}tP`(g3_K!Q(@7ZN2%M_PW)3h6o$>d*NfO4{M-V z{q(OJXtTlxakC0fi#~v?%6jdC>d^0Wto8>y1RtEjtWvwGqUMx8r*Km`KK$9Lyqqj< ztjo?CoZo&J4j50?KObv%C&#ryt91NUe<-Yb=Dgl~bDwSZbKD#aL9OX%XYCrenyw#b ztAf>e2JH#_>pZ()R4ahjm-TmUY^m!%oCfB0o?qc7W&IZ|tthR3qpWLx*8g{WcDDbC z^W%@*?~mQ@kKON&-S3ax?~mQ@zn$GLG}q+?7*xG%G+Qn+%;h#@F^9`6E|4ZKDgF>O}Y8Pid zG48Y{C;ss2ykx&L8-f0(IYIiL2k;KdO?)u1tn21A=vEr{?~BXB`{s#X)z*_?8#Kz` z#Qm`RQy>Y%pp6-J^OG7>#Lw2eotJ-9q< zI?MInOEH~a|7+w{1tqV4T`O98ME_ef{;dD+`0T9ziJc$0RY7+*A4~7~X1NUV80FUx z>6)cO$(MU`do#P4kH))bk2s=~jK^QPDP2rHf{#K5BpT!GST5<^VEaKxQT&E_LiHhf$L2wFsAu2>CK=QFx6{a8@DTU;#~bx8_`kbD_aRIC+~6>E}GPnL4ib!kei zV8&~z85CY3czA$h(Qid6q2N2w@MPQFX?+cR=pyF87avN)dULhuH`}vdKQVs!QKBPVQaV$f>`0P-B`s= zph!z)Kxw+fQ~=~MD^?)#DNB-*R;=hlgG`ZdI(2Dr)N4@vc`=kQrf2B-4$Vtqb)Qa#ddmAf5lVz() zHH<7UO**lz-7F@l_ne7FUg4Z_j>c%2Gt}ak!iZ`)wPnF+oTg9C)KfxJh*N2K*P30;l?0Q z{h~<-WCl~sDyHoHVI{o5JD>&5s;=;Y#?WG@=_@Au@^eOYK9Fu<$ADhh@faW=QD)K5 z9IXkvJ$WC$sS70(dpE@pWbl;pRB{B6S5#az2ty=^s$rDQBeK`G!4(fFarYI={P-K$ z7E<+pD18aJ{jr_g zD2|S>$kQ-Bv=E|N#4*3~ZsyDN_%-r4Ao3M8axss*9KXIUgetKb%F+GJ+{e+TgUmj` z!LFA|C0^@zGl4aOm)_g6|9TS?qA;Gvuam{=QxG3pBt}ddbT?j(1gdbL*n|?J*D;E` z9Rx6+uU>g9%d!_-i22|c=Z9XQ)w>&SxJ{lv zhPih{ElQ7M{v8dGNw_-U<;3@RJ_>m!;n1j*Q{YYkDrkf-Xl<{;=Z>=UE?V~sN7nDDVLa!f2Ma$W`}(t{p#r{FYlNcl@upS;$M zHZzWsC5{kSh{#Z$_JiB*46ZZRB1%riM`Wc<%yf|r7rA)LDcrN8)Yr3m zv3`0*S=>_A!R8rW;^Nv{i3nY~oG?V!6P zj8gKTz|(Zk^+J8!Uy;q&L)xOFzru}@NZ>#Ck*jrAK5D?wU__yJA z!91gvQcJEDtDF4gJ;(aL(GHFWq&G9vBVt-b)>j^5qfs0T z&oosPu^>+wv&dWuf=|D^jbA^4ysq=5x4PjpCZdEEUl^G`aW*w8PZgAW0|%z2+e)S? z#Ei-oUurd8Bh4bS2k&C4*#|5SslW~-)M2jp+(s9?ic|>63M=TkPFoUFnuJI-VhVaj zxN(&%u>grHN_QUo)RuT3!)D_y=*ie5;@S9YQ;ATNJ|{f$h~$~#<|~)lnvoF*48I0{ z7C#1WG@i|P8w%}XY`x)%$xJnG0=MX%hM!MnH~y0Gig0vjMqQzVSGH&j4VHtMFR^41 z^~tWLc+VG8Wbswjcpae>zUY6^9KLZCxSApJh!v)Z<*7ZM1_%xpk}%Z7VL&fN>f^4` zOE`HlIolGdcsO~WbkT;~1)wdV1kxJkz2uTM5sf(6E3T+8vlw@tP=UAtq)=gyOkSLo zSX~w~!qH^Cn9EJ5B`ffyF6P?CyCO)X(0b)cmaN2*bg6Sy1Z$nCTZXL}Wyxxn4(cG> zm@7vNM7Y&5*MJN_$e}NEeAb2tL6p?JN$bh-i(Fg{pEK6Pl@GEY3zevbU0#vNFg%ki zN2U8#a%G|xB04U9cgs;z35RnL%L9rz8gSOq+>PMPj7gPg@xOBQxup@;HA$A#l#a|2twM5BE~TXu z7Lz8Vs8#0JYvZpl&T9#vdYi73D_B$SY|_ ztmqGpxKIQUsEXN<5;zb(eXb>Bk0X)`Ild4O@=Sw!3?Vq+Kd{(B6N8z$=$?ym>xKo( z0;e11+_ibukcROqEA$8o>q}IZxKwcAf#)Ya*A=IFkiS6`gqX5QI2@3l>Uhbe10y>P z|3VyV$eEd%Wys8(vI5d{vGNK9NQPQSF@{wkMa?oJ9g(em;Ikdn7j+|B0H9V5y-f82 zdB7+&x1j=%*Mf+Z8FT`G*OR8zroPXbIFU2dqq0taz+4ql>tV@9lIsFzIldgL9`+5c zrfWja#?>)dPZ|P}II4(eu)#y;;FV-`Pq2_=wT?+GMxqW2bEcgCsiv6mINv3n(NVQf z)Ycl=62cQ=F}ox7S}_T1m|s*d%EntLIQ=^=irYr{4;}Vjxonq;WpU*tK_K5e>xfmC z1i54Ysx-LiM6**$RhAaw1YuRVpnpAVE{%HFrBw;P3x-@ld_#;1T^A-JDJEJq4^E(r zSz?PvEMcu=%T<_uWT92j9{%{vGgV@ahD=jMFUvgStZDs@uE`4u;kr~Y z&nodD9U&DG;)@c#fthB5Q&!>N6dbj1#}KR-cbgD^Xf}b55gU)W5(OWR3Q!@DnicRv z_J&iX(U+>k-U7I2;`oH*-a<`gT)Cs?qpn4p7VOO7sV{pIb2TX^PO4xYkl8qbUec62 zSNKjB`7ZR3o^z68FnNb;d%Qz%LRMg$+g_Y0#Jww+1!_OGI7yE4Dd3}?Np9Ey3q+1} zMoM_MAcpNl-rFTXAVm+u5wJ~8$PIYvP)OEgyEyM1#W`;gQP?mmnr+w>(~bzFury*t zSP6NvV7@z1wEQ-REG!r=XNU;wE=c+^rR31Ti(nFjLbc>G7&i_PLDVBmId$p^pP@Ax zz6dm%kyk|4=4DF$C0UEe9^F(FP)Z#-Gq6VmJxL(Z)r*7p!*C8VQcmyC3y+_}%w;mJ z+c+mLPgf2TYO=zmE_^}U@IoOa1toI-d0ieX-=4hnc+BGUDO^R@}yog_cP*ULt6}F)w4Sa?5gEaEm4{BcLyj_(Y9G-aW z)J9umNT(=SstSvHgUFTf&U2KRs7SV9p%9tbT=sR@0go+Cp(cIHU9OZs6J;aeE!gY( zo8>*nyW_7?YI(6Z@0g~WG{3xbmMC+~vx?#Ej99XQDiHq8g ziKn1~5EBxWd5WuU9A^QX(`gso!cK|_icyH$R2quyf+K8&im!7M0_8zi@I? zRFea9vim?NxH&1KW9$(bixU#4;lsZ`5l`f+osc1Kct$tFi*X9UHg?BF?EBGZ9C5*5 za^gg262iso2O6^5Ys6KP*h7|OPXE0dn!G2waJ5HVbz~UN+wCU#fv(>bdH*L!I%17V z{Itq`u_sm#lVv$!C)jfn zbteTpHt8ot;$e3)(p2FBlGuP7TLVDca^MQc);MM}w}zXWVNaa#+>(|SGzxxJBu~uf zfN=z-S{fv)e0*4>M4*&P%DLs;Wl}pNl%=_Q&rwl&>EZj(QXog+R<5LQjNHnV?P2oW zW%l~uaYoePW{i266bigau%i!01tFgzqu$a!a=pchx4k2jE6l#MhA<)j*% z@g}Jf(cKD)pfqZ>p@$!>gi3d^J}$X1E8lmTgDl|bbrd+>74FVoYOSa*aHe+fhMA-a z$nTG<#E0cct0wxzMs4egYS=CJ#;4WvGH=L9t;&>YoNr&2TJ)A%u!?lGOMz;l!m0!a z13+$Drqv``iQpU~My$j-ENgeB0jH%oy)_<5YQf|lhKH6AZZ8BFI8IP1Ok~AXZ6SD# zV5b~$FQI@Kxo@vBk>UQeM8+zrYho2~`M^kz9&Jg0SJdI3P=P4@BSi8&Cho)0_IRev zyF<&aPt>9n6icDL<}xdyc(v@5YF_#~moPXi{Yvid~b?6Io`+ZxM6 zRAOVjMWiB11&i-Up9&rnCU&yX1*t1^t00uH`IW5`g>DxFQrtUYIF;?w4#*QZrm~t! zDcqxEyp0SjvE~-l*4#+>MDuQHX@x~Ly-viQD_xZo9c>e;t4xF`l}YrisO^tar^Ue_ zK3p-poLek zr5vXx+~HLRJ&93GUfZl9s#BK4BkX6%j`d1XqhebUQW8)s^bsRAJc`nKO6*`d=qaaX z+HSbx<`r;5zq#ZWesaoxc~k!dpS1jc20YOu`A;{Bf8@XK_(=KxgwYmq{{a^a;&cB2 z=d8H~$K?-y{cv?$tqmF^*I%K~8xD?3_KRB!^7^?gl-F;12%KK??Cx~7YBzMyDuc6f z@45ZZYS{0EkFh@dJLS;(JAYEwKfW=v-O3L?DeJ#%7-ebwo0@L@S^wYhk=8#y+T8N5 zUUXehT|NTP8x%mN|L7L_zPf=gJALi= zXNP^~{Pe-^9)eY|S^czXokxFk<+tE-tJb>*z;D$Ze^dp1a9UkAosYGD0;(S`{=;$A zb&IuIqhEE~=>NTS_p=JR9dL}c9@lYEozF8!!}tZXYmlB>-|B#B|HVODP^VjO9+&#< zMs=v2jarSvCg{E_m*wH0TLDA=_W9&?bY5G74S2d*-_)E!_x!eWJUH~h`tiY8TfXzT zJiTDWo9o*#DgJYH-#I*QOiy98-r;Sj{=Vo}N8o({+Vy7lc74(XhFyJ}E!HSIsrz=l zZeIiNxjY0RyzU16t^M^R$bkA-fb~wA>(TisKyB)~upgS$_9JR%-5H{1cMTstbFQz@ zv*XR$fzPf%)eYedG^f*b4}G}%Ryqak8nkS1R~vwJeX~3{nSjGusapg0n{{>A?l#u$ zIdHU%eZL0P;pH0rt_?aLr>MU_@7%Z2Y|!jB3!r7yy7&IQ)A)JSeSCXv4{Qfgaoy|= z9?#x?wqDMUFM9o62lQu)X7>|4J2`b5hbL>d)~mJQtgyjtP`*6>+3A-TQ~$p9cK29$ zf15SC%j;LaU2FTty#=V%AU;S3?A}LzQ(8Y+-O0!S8X0fv!mfep-ng^8XrNw-Zy>l+V-zLHulBGrqTt4 zMHNgI)e5Mcg7yM@z%jaOg3e*B)79<^{YIrZ(btQK58UCX39did%lZ&ZI`!E@3EW?` zZtgqq)LIsrqgLS&((*WHOh3AfGH3#D+l0-2s?-M!2Y1CyK*Q_=jbl}NLv)>d_~_a5 zsSh4tdE4wY2k`&r#n)5dw%4O~a13#e;1HZ&%+4SUO|a<{njaf*@liOeH6ZQv_Ugs8 zmlJonEPS?So5OV#fc9qKF4~O>D84U#4oaX_^&bbd=?CgFKbW&MA9P*+bPZQU;Tcb& z?)|Obf2_BTuiVQZ7(Oo zhgz$lpZFhzO265LNBN!8t4|(#vyHR3THkMMFu8ADw*XE+vA;WSKS$l0y4}2c2Mr5M z*5K2v7pCCMzX#=~3RxVCVk`_)OivjCSjaGrnK8?9ikhj5(H0L?bl+pG0TgY@{r^>GpZ*3s`~ z=M*l{n$@)LuMd5cK6n8CZd--TL#vpt;p{_hb(7wja=B?9`X@)kU>B z7zWJu{c%)v3J(u(dP5MC;~A)&}d^&*9pw zcGk7?W*^epZu_lLuTitwmD*LcP+0ZO;2H(}$IDk^)4VKg9%r@-H}9HrVb_QEmldbg z9xi_dTbBjEaqrTy?!tX;0lJ?M{=C-w@WBACT@BQq{6n~`J~y{;FBnXNHGej^u7crx zXBdpZ$U@IL0}G8y@f@we+R_H6LmR*y>#^%Rw_LOxZf5IC|DxA+Y|w(!;}kSI!Le|D zQfU|9SOxgu5z$(-{fm!JdjR*Ja4+)V-wYgoZmwZJIm6!LKmKOcVP_5C zPWQ9s-Us+j>^0mD3-EJ@wmR1ew@bR8*TE;6E2zI8?wyGP_XSkAFbCZ;=RDjN2iJAj z_q`9aA39fT8p5)NmzB?xMim@G&f2*E?&s!b7t&sJmvFy8`{rli#CL0GuX3KzxO_No zkGk!`BeAQm-wSA405{$0`|a`IYJIl0IzHSSyZ49dt`Coq{?)qw6O8o%n7GIOdlOjm zLjb^L9rS%iLwlWb+Ft{`0jdx8?dt7E^Zs@Ns<#{W@#S>cabK^S?u&C>tbt9i7j?Ux zL*EG|$e>nfciMODj&^lyRIi-X#3~-2UJH|ajSkyj!$$`m6g5Dp)2xqHg?f8289vrp z1$*8d_FjxC5-m0z`1`%kb@~ptscGHr`Qr?B`sG7y3U1G8?epvPS$%52-PC#ec{gzk zeSLe;?pepiY4M@0JzsqEZ#QTWSK;sG$C-Ol>jCElSgy0^^!u0rIB$Z+V4}M}SH6$V z*A41O5bT}d_wE1;Z`Zx9a|xLP?fUZau<0&0UC{SW-kW~?-GvKcs7(*yfDeB{Hlki{ zSKm+CAMNRB-~FsjA9bL$&rb$tua@(()}2DBtlup^_Lqp}V@z|kcG#?*&K{raUh&xO z-fo=raP6#auV0_eYF+JYc5(qXkWKfq>-4&VL+8n!f=l~xxG^vf)cAOxK!zk(;P7PA z&qr_9#hc;aW%06xdwuJ=IUM%yPfi!**2|+i{CVjQub+JXzIyKW$EVHWDHy@O;bE)! zv7Vqa0iZKs(S`?Qu?-i@;a~{bh%o|gz1Mo0^lGCjJVy%l&Bte@>%c?p7#_x5=Os9( zrfEd-G2P#CmJtz+D%(YWJKd-~{rVZz4d+GOs&5>*h2<8OT+wcAZ zxT!vEs!vAs8gvn}Gw9a3aP3_+;ds~dll98KAGjq*-x6*fdUO4;DZn-K(5h`F@b9(N z*}xUvo~=<`G_Qx7hjq0(*PI4u9d@1W&r|RmblPSP|61_;gqu?x)DHcVHQcB#KYRzB zcYej~G~GfM2z0`3d#)bCjkjl$b=6t71|7K0hnsQfVXA4MfDfJO^cBpGe=aT%zFb6^yr!BiWX1$(JOyqaG)5+MM+!+1TB7 zPnuVyB+BMSB2|*|rC#rEe`f|40w6$AzGU08QFmjB1ZD<A|~0p!@U6tGBby zHoQl~`By(3Px~h?p8fUZ%EhaA!^hR+I$Cbo-wt5q3G@4*|MGv2 zp8fhivA^}>`-`s{;vPSh<9{+6XJLA$8z9Ta|91PyR>A+<+4$=J{UV<`$Nw4f;R^c` z8FS1~KKoOa99%}mq_u+oI0}}b)Vw@0!>pxIsNEPjn+|cKei}r>Fgm4*p#_%`GS~+B z+|n+4#KX@FV;&gz#3(aO;z59S{C-36j&GHx5%Iyxqa;Qcdjn&NPz#^htaB zi3Xln$w^ch+TM89(E}LyR(9I!U-c$_`k7)RH?}$^Mp|we!=w^5L*uSz6b3mZ<*WC^<6pV3e zre78%9}!LPf1|(dZEGdWd;bKQo;)eNT^z{yw3CBvcQm--o*H>P zfWPK;7S29D{G^sp87m`C3pXE{rIeD&IRjT=k=4C$GJ?{>nx$Pygsg={M0a866$nu; z`%@2C6bp95JzASP#Xb-Ww(?EC;!l-{j&awd#rP6k))6^s*|7|%JkDhTHxy0oKEL}fj=1>aSDH)+I-2QoDQj9S&RtnG;~>g zUg5{@-y9w8Do3nkwzpE`xdPBmzLZtz2_19Oef6$J19SL76`Q54)F`IEv$%SSfazR$ zXr{CduE^DT6+*Al$Li)sX9|aBN?U5-i}BbxOwcX$vQb!;Qeo#4kh3&>3)M|^#aI;KdYze9 zf(Jz?cfUH7)69LLvmh5~I3FH&Z--j~Tbj1uJAV&}zvjevdrbPql}Ix4;E2>z;LJMQ zWT}q$a)b=5^qHEKyWP$gU#0XR|K_1-ez&*7r9O|oxd%d3MI*SwdG(AQ)|kHUgI{xp zN0l$$AC%VK&QpDhL`$%~QE#@t4?>~<^WFI8f!H0}`9jjIAT~G3m2L7bMndn&W5akF0)s1w|`NwSAxGDTvd8fDT<#vJn~7s@7}l&q!v{S zxzop8JABa+4S8DySwRxrt!~;G?1q>p)cAUXP)>_g_=qfqlcPF#Rl|Cl6NP9+$H;q) zw!{rG_thUDY4)z)_W6pr%sjUqbF z%m<9YA|i7~+it%LRrw~48id1abmK};CmIRNii*1lo^EPR>$?CWKt_zQa+7IYS3@1L z3s%pw4P$rg!yyPxUay9Y+LJ8k@j5(Q(XV0pi+5*2r!ZGP;HyignM@|J@8 zMH2#|5l58AqTD+U8TC*-er|_CA`ro-m1^*oO$n9ZfS+n_-yM0zcTgV+e5DKI45QEQ$FrEBf{pRPZC!M zaF`!>-oFfq=(x9zn2foA^`5B*0dzyDqutYXw>f~Lxrgz%a1WYruAMxS3XP2mH3z8$ zNWo&AyEi$6ipbDsBGgE6d>Er_3O$oy_~41~h_m1I!U z+c$-P`F!D09W-HBQZ=h$pe?tNP%m`EiHwd3M62Z9w|Q1`+r|ZXkh0AUE?i0^k-LUa z3UA)$a`isHs7D5V34d~w*U4l2F$%w(zt9TH^M3|O3LrJ42d~hEF5b*jo z6*Yf24Db|cp&g{AP);p;UyG&L6v}{W>Ws|GPJ#J^!&DHLw*vx zK)mnunWs*~eZvFKH@&C$uqUoXRECMDo%eNL6%_GWSd<8+Z-u>C23vNDZv!sJv!Gj^ zRD}onH4gYdJj=t@=_$W(W&@9z31MR|o)$@yfYsRXKAqZ@FN`7X(+OAEB&A2RK7(SJ zAC3i6ML;lrEYBV1v8&>7j#vv*<*&EoJDG`J-ubAUVb;tU*+^YqFs8Jh@~GwGSI2*T z^Zw}I_(ZQHNoVCd8)jc&^tR{&Lr!Z)X6rZd7+CLrsG7lhJ9O$EX6$G3 z&`EAd)6XsaXoWW3m2=-*$LOcO3tCB+Q?56SFj%^NuT}`Gaal>>ttj9QdmSiIXnIFE z!{`QPwu7pGJ6^%;uDRk|2WdgmDuF$mpn1Y0b%55$N0?ymCGycg^&mlw1`aWYZo?S< za0nXy_|TMI+4W&b93ltfKK?9W^tc{4K@~dRF(bLcrFK-dps-^^nuk(x! zf#6Y%9^PQR$!)g{tp|(!=UAP$EFD^0#f8EkSFOmBvfS=5(|yS6w)g{M8R-D%d&QtJ zurCaEJE+08hd)_;>$Yd*2nVUf`&d!h;!CUtzhId;tBusGAnJm$v<4VfYAs!;-Dnhp ztX7*0;)rj`uc!68n&T$)&z?V305H4m^_vgJ^+4pu_K3ww@JEfB%DUI1$?m6mWb1pq zg!oB)#J1cQ_z_`v)r6~8C*P*e)Qh+(k!@)e>&X?=GBIk#c17jw0!r<{j_n?AVK}4z zU3!~b$_wzI&nyItz0OXqW4K6b$KFa{_)0a)9n|V^ARR%u%C^8>$iEh^y0#&i4~6^c z>yF0#d7w&|RU(7EV7lQ;ii!*5xv}9cDQ8UQYRXsFa*hmf#iNWv-LB;RiGl^-xa7@> z%DQ+oJWw0l875f7&qh|@?WlO8UcoTA^)gkrJy=wR;`GrH-#NWMWj>UFuNN7JO8NQ~ zrdR{cK-N>Nc6f*$kDf2y88b1!5%2qjy7C?U>5C$2J{?OLfl0A*ZKZ@?MQx;B2wf~3 zWf?3iCfqG~4iihUZO3xY`jZpF9KUZ`~g zVP*c;v+(o`Z%Mqv4S-eopEtKV=KX(LU+@3=G9M%Vv(ejTBIvWz%0$plwM5X*{xVv5 z`InQ~`v3d`?=+EDb^Pt{YIgqTvmbsq-g)}#n?p(p{rV?N3jL2~2PYp^4qmMP3(H94!^x*T!QFzdQKl$yS|iR0ufOubP!4m|ifg$clmN8ZW1x893!Jor2~ z^TWtH3j2wlT&*pz8rGLseUt=&m&T*)!cT%-?<$_boE3RVFoYQ~3HviJjKa+Gqv3j- zU_za6#GL8ya25@N#LLbC4|-#gA{F@KySG1hN4Q0pc;8We>aq8p+*g2i5JYK!8x-Ww zO3%Oo>@#>+^EDE4%!%<{qnFmt!Z=#>0?>Q_?>tCS`0aHBE)H?kixYy<@H1>f;>A;} z*aX6_yfIjJvTh|u@`mGCLBettPoa%x02^9;5st@RKk#O0Fq(~52^y64etdKC{ktDd zU^V-9@5h4=9}eE0{C&?ul^w&|;5=Zk@Xpo{KtmG~KgzD4B?RIxhaX;k4|NV+yg7Pv z@^@&E_xjDr+r#5y@AbP6-huc2;KRwAmp>dGd;kON!~1u~hihP11V|W*AF1a1h`JD1 zI}C82D&@TRJ9Iirxagf>s7n$Ig76$@1iLVvUe)eb0_Kn7=#-l65=mIPkGv?(R=pIc z-#^Q;>F)aa#l^+iX*64llhgGvgO{#%IfXBQj09%8%5X-`of>4iGMory*L^K3k!b=qrrGK47|nHpeonS7V{_j=X8B$cVQv&VKD(K z0pJi6@~#&^0%n8E!z%A)*>r}_fY~5egWxERKhLHxX7EREOuzQvZJG^tcTsep`7u@6 zTe#UJ7uhd+seRu4-%Sc|QF( z9y`|p(ydy|roDf7{z% z?Y}Sb`D*`twg0}_e^vIMwD|bCSTXq)FXCiqJj#Ylfv&&zv$Ma2!G+^B4!D$1ISNeU zBwL>X5PV;>Df0){3k$YsT(f52cax0HB*}+<%;Z%Oqe?Kd{h=CINrme3^J9Tp^B_5iqaQ$UZh?r`oCnzvXtnefsHonYh^Dv0Gd0jG490$%dVdK(WnH}n zxjBLg0ZKiKhVj^XN_hjo*{fZ^QdoH91=;tmCnb`G&P!%%<8Km155`TBgu}pN`#0!e z#|hv$6-j$QZZvGj;(Kgb9C-~aBMSvkrrGqw#-cJFjx#@-rMtU_NfIY0qcEX^T4d2_ ziyYn!{cCRk-bKVp!Iw2kSo9nSY<1IM5J$uO6)FV&Y7{1ECf*P!)K91*8c>w5-YjtT zF$%qlB!nfZi%+XwzD_|J3VdUX_$bOVrSl2s!P4xPMv%&zcYki=B%Q}0%t=GuWvYB( z0}U-ilxPHCAw-)um{W>c5(+YLvtxF>lGE>SDjQd%4;m!knl zMV3pO_vpE|Ay7<{@Ei=~UE#`__)}HAYr~8G0GR21x67fEyQ`+ZtIF5)MI2M}I;C!h z#XS#_E*P_^OQ4jEX^(V;nW5GLk~D1Po0$8;mF z!a%cnsOS&{UnliwQL?zc$X{A@-A$$XkRI6LORFC?hJgn%?=7>x^+zx%02nXCMq0rM z)lltUW*s7?Tm1KB9F4+LSWV*}WB~iNrje|fCfXa~8G}d1;%F7y8^n`I95pzoVK_jK z2Q0AdrOzjIOJ+`>{Aqx*dXIA!iN-I=d$#*wD}Zu~Y!XXZoPUJ)s(b}NY32>i{KQ)( z#-20TMF&QMq;Uxz!b*UA>T>vD!L{iuJ?r)T!Dqy@HlW33(_#pP6I`(O29x19j9`Hb zkc!P-C72&KJ{9M9urRs}!pIxb^4d*So{S1wShwXE%Ef`cUgurSkT!1wgH)+g$M*5b z!O0KDB>8J}%NG>P_z+g~G0ZL!X;n34;t!|*WsHujAV#vSDi z7rB%yT16iks=;oAa5~s1Fa9f$Hg({=gJV3TW8%=;Y8lh3-cp*bs!D|lkwh~b%Jw5S z(ow0-qcgBP8;w{n%?(kf0)E)tubTb!f0m^WumfzfmG5Jp77Vvli-l~O#+paRI<6S$ zI(-TX1G)sP3^>y;xTkGXZO8PMszhhBwf*mpPd>bP`yEUN`}^MF&%#Ui^PoXQg1Ay&8;odMvgCz9FI5Fp_;0?{pO(s!) zysdG^{;#S}?i>bK5&yUSWM{{S|J~T`biVHYeu>Z5{ok+qzhC!%=ZXKzgZ)D83g|A_ z_HLQO+Oe^F5>5j9o-W&=a_vB!hej;oiNlyNS8uSFL`_-5v|12iQh2u+(;kQ$6%cv#xrV+BOnvY$49IVYqic z`)7NlB;3oc)ZT5j7IcQ<=y1qAduhtNDk(D{YqJB|;G&`Q)%yC$yI1dap{Q0f5n_%wpx@rmji0^UTh>cI^w;q30AlaZqc#Q;bZAmN2?5V&Do?1iSG%d2I z@1-*X-WDQ~%cc5sFiS)r3IMNyZXI|;SaF|AFum2yYsog;)ESy=JJ}qTC5RL-tZv!P zvZG~p8qal@zz`_CL9jRkL2GSgP=e8@u5E4$erN-q!9w4skl4bmvUt(zQWbp{mpfkc z9bkr`%cw^yBn8dQ5Hrs8gs>$(~ZJ2+$b$PL^o@Jlzx0^asr0jeb z{YdOdm<}ATm|pP5w~GO%5bx{^O{%gIXk3=~5)#L|Y}`8w##7K!jsk4b*V(c^KzqY> zh;e}}8_wd3UKVHmxJMn|P~#$&_};wO{h%!m+!>$>9#z1AC47ed^;cll;*QJiE@o9> zP|?)oplMfu;0MugOip&9VHo%L22BH@0DA_X5jFf-^>8QWM;NKEf>GDQA=`r$8yILt z&E6PHY|uHW1w@GVcIr15~oDd4NzQlgt8i2H4M^LcM5c61f@v73q1iW zVx@=_l)q3zJPf9=h;Ht|e_AcEq>+U_h8QyPX>B;0OznhVaXW_}dymCx%3i=S z3X9F5v^NjZCdOd`|7BZ-yeu@x5QwwSjbpu*5v&8zN!`5GB#nPtosCYSo-X?~We%GlH=CEC`FNYlM8tcsR(Y1nc#I)6iT z^;xT_)A6i0F&5w>00W%2;+Y6+@G%@7Bz@|@LAv*nh2g8PL`d6ZtDBxi`4I+#rc3D> zDiABYmY42!_rPYovUDyjMChNZnw+?@;+TL*>|!o8{L0?&3Un<8IyC2Q*_X?;`f?ba zJ8Y-~SKK{Vzt5CjdmADZahaKg`*aIgi6aw)%R zYQ$NkNFH9oFrp;Qnw7=)X%@G%%_|bWm9(~u6Alf5w7v*WVRrd$zq9=W#JJP-vdQ#% zgSI%~8%2^&X5+>(Sfa~UImBN%Yhe)q)jQie*BFf?s{!5Aw&mYeyj)6-y5w8K_C<;+Ap%|32^syRKm%r+E%cm<{#;uC5C-M?9*A@cV& z8ws6q@b;g39diiEzGyTUaXjZQ(zx6NBAXwn_9tsA(O{gfmDMdFBlHWmV-#jKpB3|` zoWi_J4G8JhZIyn3wU_wOY0zkIbT%tHO(7cLquq_@DeHOz1ISNZcEB{g=r{&1l6F}} zT4#H^O0SSgNz5rA6^Jiw+Br6%L8MToa^AY*$s(UfOkXdWMnbccisq1-8HMSk)zV>~=Hbw$yMWw^{Nq z?l@;gqNvsyw1NZofT7zhTRG3q>ECM0=ohi>)_4Pc(>l#+F5B(%y5_P|2ff*;jAEDmF(Cb`j)Ck)#brya0kl-hO%x}$gZ|H2&@XQb{{O25 z{>)E%+11px--t4s6;P46ltboDd4$l!JS>^rPn5(ik0=AhuH>RPnbA1DXtY(afx1?x zow>nwieM|TxShE*NN4L5{5lGl)FjAHDHY;T_$v9eM@{YokI0mf>& ze2Iu|Qiu3^Xyrr#!nl$Sn4c3&Rf)_mG{4bEDFq0wPueU>;<-1e?n@=O~q)ga93>u zk8AmmDO$wq3Yk?qOv;!;pBv zI1LET748bO-N>%IZ*}f_yIvk=zPlSK9jwB>H{v%K^^$a(uNFJnI#TC!^0N*qXUHWm zM3aADh&p8Moe5ZRwJ4msyVR+bY;i8P@0}~^I7X%<4=EZz@2!{;rXu#Na(>j^CYsAc z-|5`l%{Wk|P{{(IWS80KX%BbO8nmg`pN&RA@^R~vrqellz1GI%Q<*T1pZnV|Mk|(6 zi*bk>nEID+G%xqm`fW%35&(^j%fSYi9jK|g-j2vF#|yT#f=_wDB>=i96FG9+9V_lO z9!e|49^}~Dof_x`p#~MaMyEc(n^uB58L-!l!f~L2 zV7h4Kdungg;~GTmpzM&w!0KW{^<8MX*$GC|ct^O&PpuBiEJ4BtzT54UW6i8x@9JNR zh}a$YNJH@JtRgns<<_erZ`C2O2H9*5b?-6|qbwmm4^1L%_)*f|bPW$-`H7lLtr&Nj zhsj{AE@pOZdGsCT2#3=eng#=Pj&*oLhJQ7SROdO~?Woe}IGoSP%J?YtT3Wi8TeOL_V{B9GH+?g(~vxWu345k z8j+5IH(KxoFo7wXaSP){c9BvyKG%3eC*^09xl5y^g^^ z%-{1=`P?JvD<2YSM_`FZ166t}#(plBVRqBpt643~q#Uc2mDF&q%kI;8UZgWaF6OQsbV^)DXVT!4;pfV-f5D70fZl{xIqPmY+ zo&Xt>yb=zK2la;GX_%!S(VAY|Xm>WZws)R9edhNE!(g`HGP}f?mz>LFeYx-3-Gr{G76X;XE;}L_g<1 zp*;lxd2zd4qTBPF&r<0q`V-|c5o6PRDxEVH)nnJ&!UcJI`;+l6k|dbBOmG< z+`KCbtj*W#=SFUxVHg_NP&tcOLAvxu-3rZXXnUf@gp_;?KQTp?eZ(!s@RLTp!A7kl z?W5|YHNKV)*vt_-1;Bvuj1LahW7eTCKOa$T=z>}iljb9>vbc9j@^&frq1rXIkInTM zV5XDBbdsUM3lh{tIXt!_2W2Jog@NJVxVjfF9w;&mJqb zkk_KOR?BqY{qs3_)5Ij1!}Aq*qsQtL&LG13me-aQ4ZwE3&&OeP()PSQ4EN9aT+Z*- z!0Bv+V|@!}m_g2%(CArjMNWJpvRSzGWwjESFlN&5GMZwWLl9r9<8*Q}1@rq^5h`lu zAs2)UP0jV7qp)i^$XI$ypN^(>3ltcooDLmE!u`8+I9}6T;vl-hp~Lxf&n}&662E{$ zhc%5h@JlSb+GgHS*C13&-V^75!{m6F2GWb8@s$TZ zuhD=08`SY9O(H>1#``BwFf#+O~+D6=GgQjjF)-vJ5Ad$ z>1<}n=2i%qv{T|t!}hL8M6x@LB&!|?E~6`3vMc_K2kqpU9e&3W0q=Xj6hJj1#iV8=3}lxo4-rL91TtunFjtRDXgO@EN#f+%2Z z(%IPp%O2!ql{3^3B6nVodgCR{Fz4WX3>Zx=<<8#br(7t3RnVf#Ru>kqy6nj9r{DNF zNNBTBu2`n5T_{kjX$6TYm7WG0R5>oEa~1svPBAI&#T#>FX+9yjzN)*^U)WsXsU~)K1ZlRri#Uh)dyCRRc?i zkVaUEKJ{E`P9WOs@Jn%uUMh=@a7TVr3eaZ99m)|*rdcsJPT|bC2rCgcD!rJ67%Rep zOI+d!l3#tU*{-oRr9Hxxl~YC4I`+&`zX9F4J z`;MV66xc9^X_)+GVTNsCB-oTd17EngNYXgJDM+m@+gQ2-Ti5{R(LITi6@1LzA1A6+ z-5k77RL8@!0*iU~$`7Ib^8|(^IjG9yz!=rupr5z5|G*utP;V+3$|x`5*MN{w81b`} zB^sxa8}1yq)E5`!*3iCd zpIhTnF9}8u!>NK)r9G7;qKKVM4Wl$;Q~eIe8O-Gun#ozO16HKUZOfrv002P}M9>|W zG?Btrksr701?B{~4`J<8OKaMmtDofPua;u!mNspK*DTzz<@md;4yf3+V@wVr%2!QU z$}d0>BE-}(rhIKwRd?ClM$Wx=8)tiaRebAIjIg`{^KLUkTuYyq%>!0K}xa0r0oo z6M#Tl-BXs1;tU6T%C&8CZ6-r&YWoQgNF7%}8CvptI5{bGeA!9^UOQNKSJMr?d`TOP zVGk@>RAjdMU?4XcD^`%0XpK!mJ-joeA?k`|)50=Ld(jNJ<#sKc1B{`-%E4o|QJjcD>*qs(^=@kB%t4KShtwJv_- z_c-IK)7Sapr(T>4DOa|AY0a)*Uszwq$tm($E%^J`yDU8LT5a#$2l~E&FNK=Ja2Iko zDi1sG&>x=rD1_5E4bk*eUZW$OhyDcE1TT&lNrk?kGp@C?a>a>i%Z^vg3HcFDnRw$5 zCO}YvF-#5Z8dov^@1~%La5$?5k zSu_GmV}_>x_)5E4^Kt62y;{7@jAR_c-`M_J7yva^xKMa?kYP#*Hi#gyRCT9O@W@aeO%<*BzknPdvLlViVI_LUTL}g zFt!=DWxF^vMudqLyM#dYf=g%iWyH(Y!gs_j$D@j}%*taAIH+IYW!u%7$IrStAz3bLN`hDLUEYlq=tp z*>oJN^VS)zL1YD7Hw3tDI;98N=o3aEim9lW|YwLc+ zr9-eaIbrQ%v10gDYDnNKrW)z>p=9x*1PfP{_)}_IS>v2(TB@l;1w}u(8R9lU=rsdo zoXKMh;!vo876#BLlJDv?*P)x8cS|s4%y*uuz!Sx|abXBSNL*TxolzX>%0oG*M$L$3 zlOPEPy>U1Rvvgk`>FToFZOxhjMsbD+4_&f5TTMjUmHl7~k4KvSHevmV-w!VbQM|iL zq~Rc2^%j|epeA~FJu}!3^xEo3YAmzP`be#Us__N8W}Y1+={A6*rYmJBvJw^P7h$9^ zhM7kBU9(vmJ>?80%GKdako*YB5 zq`P{R&`)+C3mGn7gXLW-;C~xU@eL{C=I(?d;ViUWXZ$jhmkS(&G>-^koJ?iTcUCs? zx*p+nElL=IERMagpPb@1JVMKPGqkKiJ>Xww5#26|uTUh!8wx-y(|LT|Ay{iCkahu=0&ryf416i{|zs zxHd|u33;ROrzM$yzG$@y4^-@7cFbGE&l3$`h+*{-M;xK>qqv5-Cp(5Ql`1*TpQL5I z=v<-T1~;$C;j;a8+(!LXNjA;yHoGj`cE*!>VozR*bq=VxEB;;dC--krH%ei>2tmo^ z^+Z`ZUSC`&p@8gieZs+ENA8u?!FCyS)F6G_MrTdOwV8TnXa1%XKCs^a{|JHLIY1Ln zSiBfiJ}yVX#H^wjGB1{;A!^{T=M96AKO38LD?MYCEln6I?#peMnPKfdYawH5Q*;J7 zB|Z4{zKOX+#$8D@`67PlHHJY`>{XM`!Q!kL^h61lz93EQpS~NRt1kt0I$+M20bLT5 z#Id@RV;l3iR%J&!u`rK9VOMfX$Y$x&CduKR$Z%@{nERBu_aBvc0~4+KNXl zg6u6~8H6f8ii0)ob5KZ~gx0IN^ju>Z>By3l@aTRlG1zt1?(Y5t%G3HuMn?WeGTwb7 z7&1SPzo?Voi)}GGPGHzMZ17LThk(i3eN9kq?tz^O_<0#B5XYYzbV=lf_s@S4$)|MP zLY#4_sE+Zeq{SKIV?k%_Io$r}jle)G&*X?D(D*1#=*T*#N1H3W9Gy4@Lpc6Cn_`%r zKqlbj9Yxiu`|ADi$%i*@zvF$ywzb3-4g&Rlq5hHdVyRztd8aWP9D!t=(x7|{@UoPr z31&L%N;=hC&cq((nkaITow~u^Gud~0_f0$+r9pN-03WcY8Ak-rRpP=bC;tCN=hL$6 zzJ|~o`Ih)mE#&{U(AjRg_?EmuVVb4)ricOuU!c7z zI!zUs;=n>pmEgcxitAB78p3k(YMRBCd;2ad`G9q>d00S^I;`)yHT$CXIk=koq3Z-F zwR@U`=UC2TcN-oKJKNjsXS=(nL4;de0cHw2$G=cU*|8VZP#jR;by*mNqilCqN`x%T z`*lsR&h(9t>8#I*k#%S|ozi|_ALeY64pyNa8N6&66@|gA(}BZ#kjXQY#Sji&iDPos zvFvtoJZL~c^*SjwE7JVr**{<*yxDOX4ZO!a-p?Mge*$vLoQnP+8(%?fZh_%kpl1Y; z0`s2L|1(q=&xRGuvTW|jxJ9_>;3s~EG=t{n0!X3tjLT9deeA0Aw zGm`wf>t=YUbThIC)Or%A9ZfvT4RLH{ZihdTRciHjUV5$`&#S3ZcV$o00gi|1?!5)` zNC@%;oipx4DPKSU^k_~bN#w?$&Jr{l8Bg%BdIqJ6Fp_k(nZeN!dGeGcvI7tOe0jml z6Jh+Wg>!KBd2UU#Szi;W-1-uVie`a%#FS<|$+jHV&Q=w!ylEz?ovj)wktij>V{=HA z+%a2IOgQJT;u>A`Bn_rkT=nt?vQROh9=AQEOj<*4lR}yGGI|~KJkX)3a>Co3)ct2J2c*J9rZ>4P{)*H2e6;qmnl0Y z{#Boy)>C)z@tNYFG<--oIy{!eBB=Az?%Dx-#})Bd4T*Q{?^Bdx?Z9F+w6#kdXMR@z z6vYt>(~~N_cxDF+0v8*yEX&#dNd87Ioh^VDDZ~1OqFGR@mX_ zjAAsf`)H<>@nwhiRC$n^ZT=&gs;JdFxkr?g9`d&xM_0z5Kc-m)TZ~`uMxj=Vem?fT zwT>qA)XywpiBHt)_>O}No&U6BAWjGmhj}IvBZF0CD3A$%;$PAl5zQd!`pyeb8?NnL zw93!BSTmhD@u0H%Bz^2*M*57K2#9QrADyGcnqi;<##NDOkkI5(z!!3KBDG!yTFm8z zQ67G-JFk$Ay#I-}FaZiA3gh$L-&D|@=11BUF#&+hRh#^>Gj+v{e;r~8Bt9Kcg2G(~7D10i9kTb(D#4#Kj>A;g73yL&gsFE z1jYOwR!`7Wb}kUx493>|43^UDsYad%kvau4#t=1}5J zm|_EeaQ25EqP!hqn5sX`q3Rx$)&X|Ap(;Klqw^0v&bSQQMw66j+a4~-IdhdlAN5G~ za=dD{IeZyxVhNH{%P#-FQ)WAJ3oTV^-`?69#FKs)1%}1NpWc3cYTsdkDtxRMI$zkZ zYpcRst48Pl>NLZ4l~C^1g!o*9*%=MXjvAV)OH+-UhD_>I_iMgVt2=kK=bXHT;b`=q zs|A4d!~v-Q@Byr_XBg`hCf;){Y?>aZG9gQq!W_f-cQU!YY8S_vyEK4}1$R=ks3G*p9fpdlHj@&=xz(c)9B331sf#tE>t3 z-|e`Ra&qcC>HNFycZdJ4g!{j1XCRWxt`ESw9LJy<6MyUqVHR^2DujzT8RFL17?(RY`4z?D4S!d&wysVr|Ic z>;|T?9_>@Y%il+*8nir6zcMWUXS)`=#}ZwPeUk?0@@AK0mfDwEdPD?>)v)%X=iX!Z z@7tm@z}rARzSi`t~o#&i-+EiD5 zpTlW79pw3_97_idOJ@u=;3cs8YPgY{fTa*>*Pkh$MsZxu{5Qo7yP79d;OE~;07`cE%~D+2_-x# zh@lHnK{prsP&F_kAtXcSLK%3{;3)?v=OS8@UKGGw=|>(J$sV+PHVHtbQQ{u>5{|Cu zCeHJC;P+=^oT?gl_9UJ90BS&$zXMRNJn_d6WNlcCZ$nhnyKmGB-a{=vqf~UtTv&MQ$&BNuY`E4iGaMF{2v3y@cvpdr<*h~8X&hwIwZ3jq z-yK=>Vwmf}QJlbPzF9ccM~_XNWeLfxKFycXRSCE*uRCzlTxhjno1%hP^cLBYx)zWd zDQ$gsao6rqLXuCs{ z8l>t?=#({KtI&j}oS4xqn*gsC*p3Ai*sN&dmaC0VSOcHB8mKnC<7oP3q3MdqTFyLx zkk<9;G~^BxYeyr^uaa+XUd@)@KDwmhE5(ZK1G-PX(zpEIk2~ zWS(rP-g78w&O*$DkDOhjL~)PTA1nLg`0CMf)%Jj;9Xu>-k-OS@4Q<_6MHDxytd+c3 zMB1uKZxgfa<;unQlp#PWSG@L(1Wt$?7>eM(^*Y6eJnv*1aUyhZ@f9G;v&iies05EE-bF-z)0b1vZe7j*UG z)?@LY%^qw#R`otUxqM86D1Xp@tldqZ70smr+lZ6?&K`fj($cX`JPR(d9(36zja#pU zUj#pBr1GaZKq+V&0wRmVF!Jhiyd4`_=IXvb%=GW&S`?i6-8@aN2gwTM0f`nl(Xpo`HViXL#1r=tD zcY=7i#wLv3D9lo}ozdBTqVdQ%`RyVvZ1o8Tc`ojeA)bT{V#Dil7(brAjzr;|d`IImuwM3ZoL{xeNU(KC=bo)n7#RaO=YPGG^&irv%*vg`#ZoH2aup0k^x zmsHt7xeNv~n+sT&zqa_rN^qc5CxIn@7vsw;DrT!QcXc6BZJWJ=Hs*LnxYQREc&Oc=g3!DCq=lFY4DsEY#TXA!O|C?;&1DcQc>o zjJzwgIqcrp`BE&l@8KAp#Ih>^ZplzPj?$X~PFzFpH;!8-5#?Cfu0aKY+L;TOgQ zjstf216MKbqF`tPV~{Vhtg_}bK1*pz4IRy*=t>EZ0lrV2+jbaXCc4D2v><*TL%Eaq zFdn&M(Jal!9ao%U}p~SSb}RM)dxZPj4y@2Nvn)_sl*V6i} z^8A5yeGM=%Z5evmcD7tuYS`P}EE$`#o9F?qoH?9c5V5_o+zb>63l&iIzKVa;bhQAyhIDa&3VxeH2t@=ufp%V9tfFBTtn1tz z28_ElN^@ciTAXsBT;9uW06dCMMf}kD1ZFALyYTc4_R`271j{h1pPtGSVB`l^9$1$5 zEFJ!oE^p=TVgUG#J)o#AJX3(Bd7-s&a2|}sUcPuZ3NJBBAB+d`F^co60v#h_RTO9L zl>vr+dn_g75fy;Bj_0{F8;0bwS9n7XiKaiDVk|42C}0_n=-Lx zIsDl#<&=>b!Aa-SfL2E6J2r35M=9Pz7Y@Qqugx?|%pTDWBK*ZYZuYI$5Kpc-RdY3% z1K~OBs~f!_lHl%&_8XM-uKE7s4Y6Z^t6zEDnTOIC_7gfmER^vAK{|&iHBR=m?1Nno zt$ejkBbQh8F~5*92atH^MB7yPoZN?&T;({~0Ilbg|_< z+hYTgd^xmQ;6`D-E`b6FS<^OVY22XJ0p?rP1W6+u8FDR|awF_Owkd%nRW=XO)x230 zHNfGnB4x_2C4jhU5vbCzPPTWz1WxZhcO59QhSZ~RKAQwXIeeV*LOCSA%FDk)UN--L z^74BV74?1^O<2?fr~et^)CRd>na}T0n2h)4adGJ}c~~Vic=CIbyTOx!OeuE@e-+KU ziKd#GV({d5EUCj-@yHGPLSCnS0uX|+)r3~=LDf=coW#+q{<4?F5ki{scz0X{2L3SZ zMKv=gQ5`@13^kMmRt^>8jUFxMzjgN$Tf-G@aUTKuV3oWGG?H9XEK``$`3L{p569?2 z&>gZ%yd{`CD90uRG`pnhwCP2w%g&8vFd$Q(Jc#N&^_LObCg&@^<3T(P4lhG6n7tM6 zY3L=>eGVcT!#oLdqwPm3Jao&>!jwgPSy^JHukMXMS zrT9B{_pp_tKi)5v4M!u)Xg(U{rFr-TaAhBVemC=zAuK!a4=W_dAzA4%S>Y>mHu5O$ zK`qG>r$Y}3cTT=ggrP_MBi-SA*@HajGLdNr!7S{x`%(pb*MsB&3WU4S2saa$IUP>I9CQ zE77q(=@0!Ly=ic%L!eCL44}EtNg_!0)K>b*XKr2OR}IpPUZ z2DRa?{Ua9cKN9RZ z(GDg<+%v(TA$#a&Wy7A)hpp3;%OcuaG|{J1n7K2SBnmfR7Qgv_LvIn*iM3;h)Z5=Z%x0a*Z4VL(!SsD-roC%`y(i4Rx0oqi6)B!sqsGckAY=JSt!Q(4_XsfB8 zu_|t(GH~CjR{u3U!{g+Oi&oKRXv9sq|F*`^t_lLMY?g9N#a7uu$!T}8f&VrcJR#_p zZEtPOgH>nbJ-z^;?-s7);~~zWI4fEZbuFk>gk6=yq1FwG77^olAu}R{ML%O1fmV&5 zWDUF+7uyIA9~VGqE)r%W9a-t!yf&HbDo^7ne4K;*xD8SB=2@=(#iUO~_0R zRKSuY3T_)wu;`1iHr$$JYFv?DYF_%WJnfv~ZKXR~&AhKE^;3R`Lou(QUbjEWtbQs*g!)AP2+EFij>ALGGJ=7qL73*lG4x+ zY+i!$@MqQ7RYh&Xm@rGxxgk?574y6(>ZNp(Hq6f#kUqQA)IkXp zau+L8eI@aHc|vo9?)jb!?qg@bym%yJAvF)}Tjv9e;v(uDYDr1&j6gn8rBCdlY#NJs zr97&M5A`rLQrMcU!M;F>DMZu~mPo5jT6g2@N94A=_MS)np$+)kYUSq{io;*mIID%W zgr5or$td4%bY<{nPE~}ulZCya7))UKlPm2dZ#aj_8Lr86KZ~I3(Vlhce=HA*oO$@j z7+xRFCR4^-2@58B4sQ*i*(7}!^ASZ3yyl**Zm+Vk5^iYLzAQt17F;R-%80lurNV?$ zLeEdN=wYhCP0mmC$WhOkTH*A|sA1>JtGcION{R}jgpNU)5G7jO+}RF7Kd{S2TBwy< zGsVJVdug&I>{Upr^-A!>Ues#8xvp8$5lDY{LY&e~beNkp((47+4>4k5=#wRY=#nPRU;@J#(L@SL?9EG9Z^s?~4 zQ8WQ7MJoyq97S8UvY=kh9p$H?Nisfh(lH*Jz{jp(*0Pr_p#|Q+R2>*~*h5E^;Bs)L zm&Ye1g*(O49hY>YQ{0emeB>zpZ9!=1Sf~(O7_nd{wpbW+&9S==)SY&9pcDUd(8K2r zGWOB3vem)o&N}hbS|ygW`(XE-O@b^OSRt$!GBlp0F0nB1gpso-ON(O+5_;yS&|YzA zVkC(2k1!qFb}8U?t0sh&6GW#j5gjLl+C(@(EE{SFlLR=5t~+P1@Vu(6>x0V5?z%~3 z-3?dWNj!8_hF4WoCv~bjaS!U$cDK5uHnh72_3LE>s31x>UlW3p2g^>OAxWzvI?Ha^ zF<_K{aEg!tqNE`utdKxz^vZH+w-h0jHEJ$E?xt0OsnM)9ZXjx!J-%?wm#so!P}XG? zpnSVk1kdJ#wxiPjD`0_UlwmQ8kC|`IUbx$Ju`Ho#Rs8C9ol>m=D5>uhX|=wy(>u$q z>a5wSkIy}WIY)O=AIP$sl}!5TF?6|vqeVDnU@CM)E%xs3J6Xf|TSM~!5NDH2C}lvL z4Kjf^n-j7#%-^~Io%vvGTulQ8#_phZfbPeaw+0J!o4L(=8V>xi-99vzI+1f(q=>wi{E7=)upI{OSmWO0)_9Y{lBw%AQXo*XeW%{ zTIWX!tS%*XeGNzP^P)Cq$?GH(inQ_+9j3dr@R|mP|C-(vi`!iC`A$KAN5gct96YfW zW!rlW24O8#gJT*h`)-WWbSi-OIdZ^21IBQ&z!R5ppx*gbFCV5nkjmv~I4dyT#dqB0 z)XU-%S0}OEZKIpi{I0HwXTfEwq;j4;)dAp}e;S_mEa}m)30L`*VtMGCf$yyFyjUUl zb>`d(`etD6ei4d^%Mt&L)kTeU%H7nBR+jkT82j3(YX}Hs$r5F8)Kr*Y67H?Q8Uw@% z*l8h_L*8&g{svQQ7x*XcUMQA-Q7F%{+_-Ceb7a<_>mJI{d~=L~=%{82X|4udxcA=~ znK&rePHEy_RL=k}x<8e}%i^B4{p|*HSszg84(Da}g>xkbjT5PT>OpcZ3Jai0TlY_! zNR;W47b~_JrP}1hb6b@%ee$B9PdFNp@%CscSxx1q4C>yBKevXO!%i^J}|?fx>~QiS{d)`82hu3B3fOw`XwF&UKium z0dHC{iS@C}T%erlxX+8t1lwXw0PSQ&*-U{# zR#Ux~&J%OOan2G3oZ=)wBf^*|=$JW%h?h%m>!&V3)ut}V&b-;l-lk+ zH@8`$RCjiGiIJpKcZy>8-_8Y?QhnQvy-xM566|%Te^P?JPW>IH{x9!2b=~1Md+Wn+ zO3*hIou~qFo49iTaT~T39jXFxcI%5dfH+0#o2tH5p*VZ^#XL})at4aGqL<0KE0q(3 zQ9+6X;_PDtQo&mZ#MwOrq%J8=&Zb6yC~0$c3aZQ!r+434s+Lufv!JD(eCMLG%ram$ zS3PSWEt{_`fSjF}R?PhtSetTQ?8k%ZIN=vvET*qC<3Vp2$TUqZ%OoC{D_g8squNSo zycbDRw3uaB6;^~eEXN{?!WX@W+`QY%)cIgTVts1R3%dxfC(R)K^2^D)IZI&6V zJtp3gH%P9gS!@9p#TPmhc;MhEJCLuJX3t71d~2(r(pjt+1s9)#tEnFv+e`4g$6q*V zV#4R{bY?8X@hMisWfZ)0DS}~Vd%OLthv#RFg}m~nqVnMEv%5ZjSp$C$k8`_;px3TV zxn$7ZG1L-1au?t16pC-UVioD#z*2r7WbS<8$!r^8U=J(80??T{7<`Cb?7)n#&DAkg zL1$IT0vF3z-2?cdq>gib9moE#$Dmd^1_+RIW-}m_x_hwLBPS$cgg+eiW_ie(dUW(S z$o>)!gWcVO;jo^Uo*}$5KKN1(U%z{=O{}qRATZuf8*3n(m5LRi!?X&s8gdmrfH;(i zUwHr0P=>DGz1Id-Z_x;Z_bCgN{H!esWss($%W_sh0ZD#sX{f?>56E&^s6h7L#$+x~ z0E4U+626?6ha#!Q#J8Ut<~6`1v{!N(i&$U;bBS-B@uQmjjT>c`-db5)G-)dHw4uXQ_F)T145o?Ss9N2}X+)$Ox0!D@9{EL;ZZ`dK`N zf6u`_z#PDK69LQU&BP~8bN|w`^)DSo|GQ9-EifI$9~Fy}_29BxXXc4g$~}UQOKKFu zu4Dz^86^o%*Zm~%uk5@sLJer)%5sZ4kQ(+76)ih{nN7_@*Sw1J;PuB(w(_7X0$0a; z{Pf&bB@LX0E+y@-RB?yU(EB2{%UDJ4^cr;Xw5$%$C2CoZa}bqygAQeYtd1+{N;;0l+Ml01o#7DDP%G)|7VUhhy1^lqt>_sO+Jk>Xlk_@W)!GaA4M` z85(m$I4Ub!IHy97+%@prcwz5vXq~cHc4*zhaprPv(1pQzVR|I}87%EjQsA~WCw(;9 zg5M&4tR%*y%)72B?Nep-Kx?a3`PyhIJfuWyr5JA+AxpvHBx3{lUYxzudq##Ixr zmDS_CH)E%b%z)NzZ3scPi?XGz#-7K9l6R+ncpMexDSm6Nkf1yfsNHF)I@(Mb$0yeI zv0xF?DH8aFp)FX+-Z{4+S*mg93)?XvjWxSY81XocEE@oN?K;&@rku) z|H_~r9yn+}^T!5MeA2Y$Y|HMPuubFIWZ;`7OyN3O*9K!3Yn#(w-P$j@>{d?Km@;l& ztzjt&h_l3b8qo^0)X_ra-0`)>ZLIa9iY2LY!Z!SN76Cb*+*&@+`9YBI-jeA?L-CO( zGy6{2`D7gSojY+_T1x#~vUWS#g1U%^jra} z#PeRHZ7z5fw3WlDO;Q~&6_miwDuzF)-+i@#xv3iVWz!V5l*m3`R;48}(>v?}n}%UT88;Cy8DgF4hwO?fdENS|e*1b?BwOxL zPIxrM)O7M*s@)4dO8f!89-6URgN2}0ylzJOE%sIiefQqUcIl%8%oCTFlzdue8GC`m{$&_gA45<;jgHe>1$t zGqU}Ll1Lj}6Ja#tH^7OjYKH7iKVS^Mz9&eSHu0Dk#h;bi#U%mpX9X^1`e!D-$R_S- z>TF84Enu-zGVWnR6b4%x1fJ+~j+Gr&3T4Q;k70TmQ7oD=?Sy0Cz`xLHa zk&HH}mgM1NWZVw5p;a}@S+az4!f+tM6xEOk>h*S7sooIGw zzcxuvbGS4i(A2kQVo)wzogWE`Bp_-uYoo#oLSL}cAMD4E7@!HRv9zQ?A57f~W zREu-8_BGxnTMr#wJc~>0IgtEy7G_J{uT4Yk&;-xCWIVI3CM0Bg6h(p0w!hMSa$1EV z1y zWnES1H^}jVranhD4#t6Rz%AvjY1dI_=ED-L2VQsRQ4sAfi!ci!Nc@FMIGhxJ!CS20 z3n%Qx;7WdP%A;JHfEn?qgtTRR7tb=7zyYQ1>*Sm^mpr0ZT z_+f}vejj(e!wip5ufqUlr>L1S$~?NA28MdzL2pb_qym3@_x1g=EQif!K4_{{vKFlA-qpK%z=a3^&NqW zLtORZgrGG14BL=+>|*XF5Ps#2K`+RDAMG#Jgs z?2dLQ?fv-X;{XW@2tqaAN7RMD+F^j<04e9i-=Wh}pmIF)&iwNLI)4y=IX?7!SkO(cYWFJv z^YH>HYPL%xJ@3s3?~z~iQlNhSEX$_5>+2U67i*`{Y%NYs*T)QAy58j!z63Io@boP6 zK>a*v!9UNulVBX2CZNBMuhJ|4@jE(tzp%W%@TY0wpH6%)jt0TP!k^^c*)i>T9nrFD z?QBtbb3R!g_Sf+m)4u*9cT3`PJ?-J+W8Mf3de9 zs=a1F*gzTVF320~U&hfWJmnJ_qT1b6o93~-y&hX%vS|#BFlrvZmvv96o3~NfUEkCF z9xzKTd)lOVy+kj;>d$U$h1E++MOk>pd^>y_g<3e7;jK~^5vPoDHRN=xf}EgJ0oJ$) zEXq88FaQC>QA+-`Ui%br zx;G3H?lYwNY{e?K;>rh8#JGIm&mToJ4N&oR@Zvo8<7nsyGXul=*4;?+}#~1PJMX7JY3kI zf93UDomaclMD;zTNnG;m4N}C?Yz}|bP>WPGMbx?HhS*1#3QQkqCjhlD+LY%`UZ@o< z{1C4jX3-jak#!%Wld&S+6KrppbCl4q)0_D(0m@0JQo#P)iEe4h%kKx3#Vba#t%n`wxyC1OG|P{3oMPM!`u-AUBo}+Z~mo=7bgqF7R*lmZg=+EwMlq?`m{ok11)~8E$k7C9AFrBq_VX){B)N?fRVpoDKi&Y)NURHKg6DsgR zgr`siT;2031wJnDy=OYEW;ckjV%l5dC4~0p(PqQaI`p2^AY;SN!2ZxiTNF=wVrn)V zpFCu8y05fTHjxY97*?_S-7d!`hm{mP&pY_xC-3zSZ%G2#0-RQOuMS`5vZzrsji(fA z(#zt{L8PqjJQ1#<4F@VOhk&g(^?@E;W0qoJ(HOGa{OYg$Pxv_ezuadrm`?8jN0t9~ z`^l!U|NmsCv;Eco`z1bK{l8!RzhC{oRsP>vzFay8aZJ_$kB-b21^fFA+uKx}KPntJ zC=G|>woNSJ9rFk`3V2);kLj386pMgQvVYXzLJ5bjVEIv)SZpUN)Eh6{gln`l-X9;m zd3o4qa*CR3gC3726lb?yp83g3G{M7Bi1DQS^b`e8GgC{k72yH1P>Aup!I+0rVgxx| z+D68Ff+**Hl`T zym2?$=q!?nRW2F~!N6O3?rmI-$dxk~hC z`QQ;fO{%<$N}_=@u-`BVkB2?3#^|}wY3h4H9V;MysU;LDSt0%alWityL6sy{vPh%^ zN$0+EKMN{)FElsCC*SbKwR$IV}D6JHwRO)#t^^qu+ z(n+z!MZFq3KSl(ttXO6vmsI^L7b{x}l`gfkRqaqmTa6xdwAJiRy{$?Y+8S+i6b!(; zU$K0v<>CkV-vm?4vx0JJe?+6nMkJXF8nE;Ok2%?^VwUlOipilsg;!*#pI&nX`F1NMx(+w+@NUL>qR^iNQLnr zwfD>74M-#XX6G3&Ro4jDHH#{?`=I|unuR6Z!-ZNL0_4$zbN7kmxTgL)7ig`=1e#8M zZnCt|+F?a|`w`krrBveKJ2o1069P+ z;J<(V)6_yJR+guUV#u$oXq_S$!IUm1K!@SxhajzRW;|~wyN`mON^DfD2HAO}vJ?Ld z5W9(Jf_YftXneJpk7NZWKgU=P=c5vwGUT@kBOWe=!i2eIQ{7lm@9~grbgGEcn4V6J zosjv6=vKA8h}K}j@7I&=@c+^_#(f6|NZL!{p$an zC;r!YmaFIx#$4SvUqm30-eb&T_;}TO+`kGQ)1jotn1k>!u`sv{=>#(vhFLuI#?ZH8 zacm2ZqO)0vWyiru1)nuADgu5tHu5k&dXD9Kbkv-^@5y85EJ}&Pm8ZqMYkX>ExdTgL zVrD{=-^FfnNmjhFvV|0jYT*aW>9tog=g;21^GNm={gm(j-j4xLG5#H#E*4+2DL22TML#0GKY$4j zkJ;*vu%P-VGm}dn|5lk|~ zzUQV0Klh+-0A8D0VQd%d;|}Ji)XqC-^%|Pjb^`quWDTmh>Va*5f#~swJ;?J-8X(H{ z7ja`4+u^`!-K8>+g?fK8ayehUZbtd zQ%rH7hWOpC5v3c)d3XW$&C(A&U{%{!F56Ddk6N%{(GX*$$@Yjp;lH%SjMer`v!9uE zgj7aS6rwSVZgO-MZ8;wh?7F--zrDT)1m(w&lqptaTf%7xnf^@{we7`6~xP7Wg3t zw)1F-`F^x)?)%=zO6Y=iSEM(xf*jXkqcraQI{=xT>*3ukc9)mw{M)N={t*o30IYESm3fDB&tIw6Z?E9>BM?Q;->toV ze{^r(gSq)`c~p2(69-q7^=K0Nk*^-(pUh6p$j|??sR_0;Q-zr z_~-=JT)Y1GG)|zetd89L2|GGp=>RT18WkT+0vO|075-)PLW5Xqk0yS0R!D(Wl_v|9 zsi0if&a`A%Eb+8EV``n`t2}r~ORs7qWVIz;9ml7q-05z43rb<&c=aCds!1F#QCF-_ zfj@+n9fME((?DO}gV52Lh1{`@xlQTd)`6Fz$`4p_Q@Lpk2)&alm{xx2Uj@J52*UUR zn!A1>2GBFS-O{JrEjV6L=5db!X5aMZXmL-)MMCWnMxu{j5FjX1UV9%~;V1Yf!hha? zY*9zFc+*?h*6t_ox^?93bM@B(bFzh_ta~GiHs#N(*lP#%$!VA344D};tmB1tfi6n>5f;qlb zuZZuP*Kb~*ygxYk9&Hes6G9NMz#pzTs5>fl&(GQWBxoU1QxY4EBrM?oHQa}FL~Ga= zE&Ks@WYM=uJ2!aEqN8F8+!!R`ltoSMBHbQcQi2g1Gg8?!htqDA+6fpx!yNxGL*hb( z2Z2zX6f1obH62LLL1`xaI1RI_7Dd{yKJnyJ7Js7(Ajao3I!f3syPryU#j< z)L*V@*;JI0T};%Y+>XWc2}6-IOfXF)RQwSuW8TBS0?eVjxJWBmgOM@pfkGPhqIiV) zqaN=*R)WJHk(?E-bHJ-z^2AhBh8O6NY$H|4C&%c;F(?tZYn z2L5V6WXpa{|7yvV=`HQNh^-d%`bqKZk$6Iz{&x7`#k*rL_Iqy+{&LuO^Y-;SO*&K# zEG>Brya|xax((J3$a~NwXJPba_h@&xo1X73LiaySci|Q6^CGdQH{9V|^=5{Xwb5qL{D6HEj-ArmEjE z2w;@0&(eh4vp8-R-6Ec!#VMqL$JgvqF?FK>r3Z>b+r|i_vADLF-?69`#2XId&-pZ= z!_bRjUap?c%I~Rtpwg>MF-l!EXCUarHEov_6-D8mf<}I~%)9h8$ixxo zmmujjl-p5}2}^>rHb&+>S)gFe9}cy`4TbeWAe519ouiW;zoX!Jz9;<#1ao&chDCfs zsjkSRsD%AMd)(@btzW;i$f9)+7@vToLB{QS35-KpgCWjiAM^_vr3EC!Ub00tLBcBb zx(JDaF9Z#YScLa+2^I=E9J)~wH?h2%oSCd2i^0jfrWQVIDSbYvTQYM1U2v)c4#EnUQn2R620u4x0^T2C)Oes|yt*3b$&nQ!2lWnwa#IH*3SALmA-ZFI- z)qz)`TQe@YSQJYvP(<=ZPhu3i#H6-_YS(yGuIISyawI}>VO2(xNVCW+S~^BA zaW|5=VFxkjnL(y4vvA!6qK7_YSk?kj@I|hvKx2nV9MOv8+)qLu$fCveFii1#aY06( z#bR3!d?Z%4?%~BcP-rQ!_SvCWuDImFnD;Eu7~ zUWSlivVZ$q7hOtP%f=*h&pi9U-qZ0aNu^S$R4SE95~+I2MS;$sv7rtaWQkE%oX3vS zfBnl8fAK{I_oOW#Vq()MRhJFeRM~ej+b89c1@&lZSl7 zGkwkzf(yf5w4tPTgxo(ITT8yZI!AKbE7iyn!0hH6^3lORP7a!f$2&)K7-7MtQL_ey=PJSu3FGYHLCxRj-v&d z&nd8!iFmL`<8eG$WJNcjz3T`vzD&2VCr9|&TEfXEJgUw^h=y{SkB_T0t5Nm{(*7Q6 z0B$srfcFyGQpB727wV{S(%3#YIozoo{$gD^DPGDG;Xe%+I)mu>?PcGlb}snun5G7+ zd+S#uzy3?J{wwkKgxmt76YE5NBpt)z>N=k%5@Uij($$>GA+E_o==F8$G#>OYygj^N z&*?pz-|M#&+I>$hEv6h6k5c8~v}yW=?L9VRQ;5ciPYhyxXXa`|dQ`~T1UGzpCs(9joJv%q z;WJh;4ZV2~E3FEXc6&AEdSzYPH`#&ssuF&h-~49TjL%2XPF*awTp2E&K?`us_{O9` zZ1=7Nwx5*4d)w=i)O^}bOItnIY_bcUVp#ppw^t}1uyoaU0XIMCw=ENxJz^d5+xihL z*|fbuAw1%~;4Y39%HGzGi7f!EY=QimSV5J<(1SATn8{$yJ?)P3G}^4B(%rH4RZ7z| zgqX#pYmk1L)3GN$hXvK=lkouT^|4-%rm^{MPh2|u-98>L&`iSiEpV1a%K`qRwDi7l zL*syTTk*6A_Sjc~WXZdi`#OqCa`1ghz-Tww3Zu1*bk+$+tO2 zXL2+de~-nGc+yhVZyr;%Lh9yeqrvGBM+Y{pj_@HuHx-kT(9Z{+bzxN4g)?mdk1-5D zzAhN39PjmR_ik+$X6QJA26P;kBvp5PN7C?46rg?}ViRJLpIqr3Uy!7F{h0-yzkZ=+ z7#}}RCHY3oLMTlO6w>i+3h8%!!1CUB_FeCG-dpXnJiY0}nH@q#V0kXi35TAY_F4Jw z?7cqO-s0%r1@#EML@c)K;iad14yl6zXXz3@kOiG z!~0tFYpXIbcY}!NA~J5&!bCCDit&3rsT2Hv6l!@tuYcYe|FN_j#($JnD#h}H|L^bk zd+`4~`2QaKe>404%<=SFPMfC&d!%>^w`_oZ&N~2zi$DH#k`lDfMv6Q)_>I~dn`EGfBn=E-j&s}r-ntS8!t`g;UK`MW}cm4#AvlLREoxs7=rv(2(7I}FSPY+@B z_C(cBX5cWykQW|>`zdvNncVIGlFZr>S3Yw-?_O0gXg#>eEH76Tc_rAzeT2wwAHHUN zdD)jYUf8M6!{!F^7@Fu|PJQUX?u&p~LMNN~n3TQSx^;RheXY|)yvRBQ3q98HXMo_( zMIA{Y))B@3jQEEs_y55fYKX_Jez=b5_J5@cb8oo+UtFp_*#CdWpSj}$JDY@Y-0kbH z9E^ogi;Uz$SdF8bMvTQw7T4G@9sV=N=rZPH9Il~<1ynJa8@yf%%tKIAC3T}-DSg2x z44lp&id7qiFn!@$HK2-PP_R&_H6C1SJW=ymS`wg-sgs3~iT8bQR*aJ^fQ~58+n4BJ zX{nwn6jVnQN@(h~KuIf%Yg14)p`c5_ARTYQ8RHdDXp9T(*n@g+h*IpmBNhGmQioA#1pV%ii!%-YBLv?_)VRN){_Jq1 zmHGJ%5Q7Ps!Pc@qFLe9dOeC3F8l3^fHc`zb*aG?&)u_NR7!@!&3(J`s1Zv5WJU#jB<~;0ZWA(5SwJJ#6t&o6x0jCR^YCO!l#4l)TE${&hKb7r1qmP zKDmZqz)iiD!VYN4jVe#Y?cPOLGy9*)owK+IV6RSSixL&1I{a-f-EzJ}9y z!4cq<)+O!G=L#XE5CNQ~QR<%Y<**mMBqq~0SK@lkmhkJ+{X+S$4{=Zj!v2azB=sD3 zlDTvMdy59?BTca;_A&}bk4J#z8h&BP95y!2o95;K9OoysxPabABa@yQ`o<1KBuJ{C z6c!LXiIv7%#;6$OwJxBMI}@u{h>LbCLbYhM8WV<}nl3_HR>N-lb3mEXd5#WG(Itp3 z^jZ{!0lK|S+#_!(3a(&;Ri`P9MzqoO7)^Hok3ew0h5`b^WNL@NA@ka7$ertwT3l4u z{X7h_K9XSoG=_X)Mx<~FGVX$5XF83UN3WKm#>jU2Kuxy;@QYLELY$P$^;KD722L#P z&z1;eK%a;Cm1%#O{+rr7n#_?}%`xR>D~;3)QL2o}BA{^Ay^cC573vN}EpD3RSMSyQ zK2q%uQ)}1rrbZzsNf2R4ARN$2Z8=4#b+V?K>-SX0h4!1MQkCvsy+f{ua=LG$9^R;gR9~O;b1|!X@n?# zX{H?hQpFc81JaM_bBK0M106j4p;mthRtYp~*ZTSHISnt;%?h-M|^o<#0oOc zb(Q+CC2q?r~ z)FT&QLket|8LW6pX@^Xt1&n&*3U3CC^|)44hNf>FL*$ zf!75k0S5@cUpS%B&3ggR^^F90eFNc1FhY|^))7k*3F6pD=H9^EI10i9Tw7tvRa(*& zr(L#sX{iX#-0-4hq&3oX&+c}v*!y$(r63HwkVOkzG=vdakwAIir-Ol*ju(TKTKf(G;H;O(W>HP=I z1fo>;9WQh^C;i3-L|QEo)%1bQKJShUkbVQK!bqv`;BsUs*q|x|R|^cm0dzg=;bnqa zb6U<7Hptkaxe>HF=}zsaNnz#Ji_-y(H&XeMzl9A>bWR>w1X3xNR?vDfq$vYtH~c*q zC2G^N?#m2hLDKN5lMEEa-;d7>^zm4)Y0|o^N5mFiB$ECajRusok(4*Qd=TauN?uPQ zjXt$Za)}gr3VPhc6&co(wG28P%y9Y@yQ_#ruDjTh#U9%!TD`IBs?30C&!~buN|B(#A+Rs8#|A>XU@QL zjvzTA7zv_V%zIiy42RRfby9ETBZpO>hp^VZ$AB*2;=IWnC0WOK(WT+Yk zv!0^nV7*h|G1ML3n20l2@1u)`z zUqky|kty9-^P)F~cqiis!#4(_E)4V*t&Ya903wc+R8&?`1sA$BuN#C(~{o#`;2kVgHX7td@tH$ZxwcwpctyVf(}q) zb){bFjR4^W!DbkDzIHE^Lr0nQ?FXK(kEs09*0!`9L|lJGv-Dc>uWXl@tP{;#U>2aAUkQ z(~*?j29jit-3p+RqD>^y{8Kn%No#n0@1~Q9{V(>Tf=Ub>Zj(v$Ds~#BPU*IkT@spb zXhKQbzJPkj#uq+b+Vv}Z>J3hTxU1I4Y+_)WvC*L6RE{6M$Sb=GMC=sKeCJIa^g)-k z?A4qUad@h?J)*fz*6-1c%{8zZCmG7Z^ukz0ieLyUh;p9FPs#fW6VQ2Z9i_i2DV3d?_VA-_ttqB@yrK zcG1Vj6HRj28mG?ru00||vu%zUFIMApP3K`MvQJXw@6wT!-$>;rb*gQ;Viyl@yl9+= zFt2x;WY7qBP@!Vu~30{_2Bz-}<2XfThBAWRdr|Xy-zw_EeYT5J`arhq)R> z+ci`VtgVTIezB{rE}6(&wi^keK$nZOOqrw@_;f-3Ih|E&{L;KKK?Q}9@`4Fi?cy(Q zLy8Gu=D-RkoSUZog zhkhUpT8`d9^SPi% zHO!bL+EL^RW+P}$y+5HksohM&2kI-Hf>~ZFRT#*8I*qVr)s^ACCTFt!WQ>tGVLmBGbI#(kgKnB- zMI~D(3^>{WMP8k!H%oShXo^-k#sHhtJ-KV_AE8kIvUo)hF~{b=26H&-dGg7R5N1@30rXy8OJBUU{q%D<2x5^r?GD^(cv?U$1$dB^ygFKK) z%o3;f$lC5jdUJAgNugSk7Ltj|3~e-M8ND9tdaFJhcA8@~f!3BJJiZ$HYrBA2#DOc>{yrqAh-evfm3&@;W;E*&F6%0&- zdE*=zN&V=?=Wv7%;t@R~bm0LmYwPLmoia4(x8*act82*Z)~5c*@kcXgi*wLVNHldO zPaZa33Sro6YU7w&q33W*NyZsqGmk>ReS4>+(8A+@oOgQqoYOsEl=ZX$qLd%dO25;5 zM?#)WRor;!%qyqWA5E3ziJlWJWXOX_Viu{~kQ(I#jf|CapbpiLxD=RIH+~)vk2x@qujY&L)!qb7>b`DFPsGaS@{X+A% z+D>8rV0-r{hoTX}a`VswOE99Js;XMf=Z&h1X`>CAh1P4SOkb5^CK0C2%TfwQBK`x@ zN@gXJa1`l`kjJAo<5TO?IfX(?)`C7Q0wxyPXFw-lc=j}tV1TmrXM723ubeica@T-< z9+Yk=pU;a-x$zgeBscHp#CL$ybw0>@)`C9kLoy!bd7=8Mm)qS0oE5J{zfy*&W zSApc@Rn^0Y?Znf#u5JZdFh`=8%dIQ=oC7lyS0+#+e^dMcT96d`@`()1k*U+5EUSw5 zy@Jh0psb%Fw{mE15p|)G~nnaw!Hqw$Ni;1o(ND9 z5+~PoonF_q?W6?v+a;{T;`GzXDQQezyOcNoDX08$pJiPN=XRveuuJ8>Vi#W{K`Qr8 zCh%*XsK*-ML;cg1MU|b)(O$M|T_7@#fh^q14#dU&apL6S@Kaad%1Z<~b#>L3UfhuG zX;gaiKd*||o)RbKFixjur58bSIpBeMo9`!-);Vm|6`9>tI_ zmm}mk)+t075=@vhkp2t98)e38-YKm8lFfTh&HLb*_g**e15vLFx#qpM&GRzQzk=-d zu6ZA*c@y*T)lpELX(#5Gdr!5zCsN)Mg&)*=MyY}PUoKt!fXV#30>8a>Pl$qA2( z4D%m%YR{Z-3pvsvjM9{|0*$sC3l$j@pq9_61R`PK(pfdEr(1)ydn)~@(qkIin=Xj7 z?jDW?7u^^Q@Il+Es}Y@DEzp6NmoNhJN`vsXuHWi1LpcmIzZ`$rk!n?8j_LwD|9eWQ z|4l_GyhJNYO~G~E`?f>^&luvkB!(P5U!|LxCj#hKK9k3Z^(kG{L+AM^OcqvugU=Wy z3zND$LWWmd3@#|Pm_0+}nD@@X*rOA6hknLg`8BRJ(uR{ux)I^H;#iipR?-XM)t`Vd zCsOkw8rOrPW#v^)O~c7RX-oGj5ziaWu zy&V6(<^1Bybze$_(n z1BZ$7Z`um{*ykNE+R?TC(+l7(?jzu3PTfB3lbn84-!`(OG+uETj1JJ4Uh#CM(b^1V zeQgt{G+va(#N3DvwSG#;>o*duJdOGaK&QRWf@lq))Ngns;oF8f-O!(H`fjWBSOa2- zxGd?#86C=v@Y-9_k`A#?zozlkza*-PMCG=MgY)tU9GyYy4ERg!B|quu2>Pr$j`0`< z<-iy|1Z4Pt*v1R?^FeY;hiR6t>3oLvlW7Fdj2NRWG0{VW2}roXOC3H3t>GX>;&6O9 zGIh#gQ?hETHf%{C(SFGVF2VA7IT+d)R)gF}rnd`qsaB`sN}NtBaXK$boMz_CFNAgb zJ&r^wDFaVjWALgGol#XN%g{@P4ElE!n_&DkDSnV2`^wS_oXLi!NAf zXwJXXB1vMCGICyxTK!Lv%(TvVHZUHCauiG!{Y&e{y-PZIN1&|0)jt2M1CWYCEj7=zIY>{%NVt!UKOXlZNrfPmxGt1`Za%RQ+T*<7OpR1YY=I8TF$yQf_ z`do#jOvzSRDrZWz(o!W;velNBG9_DasTy)`C5?9&zdRcBlH4N^fwlgsFQi&R+Qia! zf}?fhXp#R_ZQ>dKB%bk4;u-%Wp7BrO8UL&zqxk0v3Tuo+yqebrH_Gk$hHeH;v4H?& zNtiJ|)B5VP`zaoEI~4nGezS*r8AX|xQ(Skv3FIj*E-nH)-BqYs{c4mbwn4!Y6r^P;h2eK!jo|i0LV#aP5-a>~1Z>6}T=)UIN- z_KL2rty!e2WBhs!?Z$078z%Ia-B(~jXVi*uK8c0;L?HPNtP5#)8BhBTc-nb=?=knz zMXTQ(UiRqfO?j#UeGJ;(Ra|ca#xc z3gP?58N&?j+*D0lGE+^m%KhVab;MlpF=Nk`XK!eAY4RAE($tgQU8)EN>g`pOi9N3M zx7QJlklX7Z2Hv3+p+wJ8LwQ;&T!O6TuA+y{_>O9--%$;9O8IW}EZ@1F^4+>+<<1ox z{!+1HuWH90tYgKvDNk-a0na^j1s|QRwB}byGz$ZX6xybr z2eq-(%#^1d6Kvkm2F_&IRSk@HX4_EXdLQ&|Q94xP?b^`=k)EnCphas5|>tXK%@d&=ZQsnOg&qUJoep!zSr zT4>GL5W747IMQ`&deCL_`2Z|^pm?-=e& z!PfS{p&f+v+5zV&d3g?-P+7xfYUoU5SM4v`2Mq$2y;_fVU7Lk*cf2c_SoWKEyek`d zyo=4`d=*h%w6hY_xL>RPN{!;wq7)KG&5~ED`EGw_ufZu*FXga#v}6NyLP`sDO0tQZuv!$u z8rc4umaSEXifXp-vg}{4gzS0Sy*Ab97~PFFr7B7DD_c$wp{ZU;E2Gn#4m#Rt?lR0N zp|=j`bkO#pletx=gm!9LbXNUY>Il`08{u!>)Hqke)yzwg<*k~~A)teBYTVx9lu}B{ z?jBcID|?AJ?V4hhloTwcC$r_PO)(9c`KBDsH^j3tVcc|GQ?F^QvFSRc-e?>+00{;PSgXGdUd=MZ~O41m2|0*Jx& z`yK*Zryr3VtZWIjeB9KQSgDBacAD@DRrLS0Xw?Y@T9use#EsCZ)JJbGalLwmyHH{^ zyIPd1*{)mb>UFWr?@EXj5oG8}_fDy#OO~t8)rLJb!aN%f@O0b={gA6_p8ZRRUWCH) zA6LVRB5G$XVs_9DB@*Hk(C59w7>Px_o%p=}*1bI`;w>6D9?a=5cyM-g;t z#!Cj>jGO^-^if~xfmQM~kAj0hF}+zg1d6-;Pg!#mr3C*64dFw?cAF9%8@*_3?*)jx zUB=Ri(o3&!e>9^750S;R^B~(HZ#1?TNwP}i3Xnisxx)8GRWGS|7AdL_II-zOjRuU? zBJqNjF%r27KIgY&$SjB^*)hWvBdb{DEUoIzF*`sI5mZ?B`khph_O@%vh|X#nEs~nj z6lz3m4Od&mR#o<@TDh&N<+Q49AA)k=afhub7Qk@t+2|AA+*sj|e|_#KAsA2rJ%~Yj zDj9nw+6f0rv6PL|KsJggvZ1Bnx#Sk`$1RROW~;Nl%9H$vCe>EU%)0d~jd7ZEP5`MudLU+`#e#`Wg|rO(W}p%%^w zrrpMgP3cCX+UNq|$`{U1&f z!=E_i%vltSjbWw;z~CpsBxZym;Ca!ttFiqXgQ^mAz_4Wrt20bs+iNhWF0)x^BYc}3%dYwZkb|uw&RubeXZd;}ZKJOctjB>`vS~^LX zw3*rklvEE`fUri;kqC2ruFaoKF+gdJx+&~hY|*A0pYIqTh9@l{Hp3QgZ66&Hyy&g9 zH~02X=r=rApbUDUlvfz`Hq3Yc_5&USSWqC{a;N6i}j)h7ei=!mqBj%_NJzh z`u<1A2`Nq+9Ubl+9F;kzThG-tsY!0}`1W|aN$pt?I`J(lMS!{Hyk)%zu(Ag`V4!Qt zTdN%b>;&~KD@cGj8GXw-5@4>yZ&?QcOlqOGJT?eg^`Hj^yzGJN1}rh}H4L=wWflpI zFu~$)hAE~Bp)uY%l|d=>FvZp+QtZ$Gu&Dk(fJNPAfUIoF{^BvRB1Xwu9u+HMpuBx& zV6wM(u&gA8%UdJ=D~X};_SmJ#aq!lP{E9ae-s-X7uWK>Rz8eqvnBVo%;cJq3C+|DW zL#oOxTbpl>Ya}DWPtioz$EM@z>w_i;AvM?WbeD5EZoX!KTWQtbpwpsW#2I%}=sZ2+ zHsA7;SucuKZy(}99HAvD_B>Gxo50J!(!BYgS$@YNEO`iF2r;lEf%|*NhW-cx`Jado>tbVwDLs=z1$uLnBecu0>Yy$u$gElE4~vq?iRkcOpzKE`&oE&=3k875@0vA^|>fzN#) zZvg?kCgC>sW&pL>>muRMcZ0epB!40+q~@d@Co4w0Y_+b*BxVbo4=#>tUInYcS)bt zLp$T}XdA(yjd6H%j9|geBX&j9{hg7+qfLMx$XZw=1aFUwpQ0}JJD}os3=`ZtI@YkV zm+ydq6)&R(E_pfMGO+69)WBsQr-rWhNHsJxY@x(SkCUD!S!I$^n5(Hw;jd1qC(CFW z8p$#`rI}KXPTESTh?AuJVrOcirSMW`GPE4_pUEyeVUs~iK4NZIsT$xtFc_9Y)Vjb* zLb9w;2WzT&?TE9j`nBoCJr8Qr;96LhhHuL38WsqN%Fs52%{@FQ7+&+>4&7#$ z-z9}()F6DTt7;^w;vTLv6Lsl?t+dKGZAp$(ocNne#gZJTd%Fhe4b7b*fj^ zI)K=-X9Rk(Pqw=q*M8Q;C2k0UD%f0!xA(pX6Wd1c=O)xVOq#TG6ELsp;Nq}+w6}wqG4OY!! zFN;72x~Am>0yFD2q~QnEy<=EOz>YP{$x;gtIOb(JA4qyYC8xv+h2X;tjM4 zKY_vfEs0>B7X0dsyBISvI8&8!R#kDJlnN%er?FC6ItkqV#v4mJOHkE+5fx%))V z7fEHmklt>Ggi27xrO2hs;qm4nIrsoB%$CMx^Y!-bA#<_3l1z9jwQy|qfc(8GC|Nsk z+f|8u8>bN~=^7Dro33!JdvTFa{N{8A+6&Pr>bLQZs9taIC8F1CY0EFmd%VkPolg#! z9RaLcB6sEn2VL8vm#meEIxqh>nIbf`WnKCnlWWp!9Bkef2jBjsEPQ)c9=@H4iEnS^ zB99#r{B-CI9bwQN`XfhJb%%1`2*d8s8#fg(ZeY~dK`$)3!~LCYoq5FvGMUoCaV8tU z%N|_YWdN^)`CU>qflAl0oWP|MR??8^v{k7O0nXt=kRVKIN3O7_9YLF3PJ-VU4ZqY3 z%_c8)fU4YXu)0~Q2ec5h>P_)%+XK{_-I0%u6(A>K(W|!cwPi)W7S(zHs3X2Og62xS>p)ZhU47-d9(k{1RBj} zY{XBaHYrm0o2R=V=VlPGZ1sz0eNff4gV)qf=N+ezLZrba`SG9!%_Eyq@q?})N&KXM zDaus}bJccaMiZX}IsG`&&4b!*{TGo_??*vK87sE4Q?E0$>M^lVJE~bmVrcdahc@6T zI%}eBqLP~&er-8bue(;SdX-~vp-Xf92=sa>HIFziX)|bzm*~tkay4KMtvWW{>Xp*~ zu}x~GB@s&~c}vnsVEvR0UF6g1k>T4NW5`0((HA}h2PFZI8>-t|2eet%Xb8|Q9ta?) z2)Et}0xY(-bc_YXFgCXQ@`=m!%yKAj}YmLv#1yJz&u;f*+-Yl@RSXK`4g$j8W+iKL+I55^j^4We`}D9Pv{ON19e zsT+$AwVDtb${lvBO-*aH7iOh0{%?;P8SbAoV)QHo>*n2+W+NI?$;KgaSITkJuvm$` zELI~pw6-{<6sFK9)QROV(W)j$tfZ8b=|Z{h?KTdZI}EOdV6gQ#Wz|YpTFj+k#s&72I_tp^!YEv)`)&F4M{ilJ`o33yk$()3Qbg}@&NQ1l~W7!zb#|OJMQS9q+iZlEm(L1k$b$F@XnH{LnOB9Rg4Hs^z6WAt6R*5|%Yvp{CE9U&EbwiS^-aAp3UcXDw1b8{qDDX-I zB)Bw7gE%hyOLLdkhyY#*!M68=g}3`#^FTwzJ~4DXK0csz0O+!AEYuRK9J~)07q_FY zD!x1&4PZr!SJt7}x8JC>IG8&HI9=2GT-fT2He1OgNEKaK7BQ9!M8 zLT#0n!+HbPxT%Wy5!Qq275eWjwbW*;1(|JmoH*CPDef0l%A&xRCW06Y@it&h3GY|j zm`fDD*;kxmbMGWuThVo^J??!~1HfQ+7p&=py9A6hF*A6^<{aN2v4&BZ zq&?>JbrArR9q;8=vx#6pT#ri+MRNewoYl$QMZZHa0EZi_7Y_1hvV3Aim%3+p$H zDQ%{t*kbhr5w=_-Ey)&aCP=Xbx6+a<1Is=GVXED!(FQUkRnn47mF0kuUdd`|nk^bI z)GNA@nr4gE(r7YmEpJXpwZ-eHgxT_qNy!#LGnG7xU~5vcWq8GBI3Gv?a3utrDk}k_ zZHa0EZi@sAwnbJFa9gAn)^FNW*-S~X#p($nY`I2Sk}cRwkYWpNr6pMgieLpjf;Jgm zPK*$pP)Upcols2~i#lmJZMf;Qqh87DJMlyO)D@2dP2pgVaWf$jkI* zn%v6_sndzhKsm$}M*CauqN-lWm51CPBz z%3M@w0PYA0yD^q((%IwAEtQH%Cmdc>LWz2D?B7L#d91e!ll4OXkkyVj)~+=&@RD^- z?RiQPr_@qXY`<-$BF1tDpuk5e|6x`}R@&7nVVB?ELU}Q#MAN zKG!LBi7O7F>m<9B6?d=cq=S8%ww%By5?2y9IZ?YnPJ4s)=k|H4+b_h!sNFs5wxvTH zajc5dD7AXMxqrk^Z=>>c?QjQFv`!Mo$M@bKl)!#OAw zzwR(@u|(Vf?b~FaIE+@?sqNM^*fsv3hOr~f2E)a5693Sb&H+^1O1ihZwf$P}2yU&) zt0*Z2`N%2dAjLIFEX+6wY#mOeWN~N=IPrRCZ&U0S;1Lx228)*0)v6HJL^z7ZL8zCD zUeC;cdSx1Fjf2R3E@a`C8jS2?hL$|&p@s@k|D{&0E;Cqcf7gHc^>F+3u7;OF_#xF< z3mj@Yjn}}%L-z@-I|kiTTISp`pcj%vN;z=Md3fkvN{L4vFSB?kX-UQszd3wuM5wk@ zN+!JJ6k(*+4i1}MsY+^^E+_+iem~egY91anT+!-;R9$#EOvdehTX+|4hZI~u(+i=PR(|z1 zOxwimrr>tt_|5*|(XSLziSG#o!?ii#YHG&HWsm5t(XFN!Y`-+$VIqS|5=>9GGhE)w zv+J@~Bv@qk4wAd<@+A3z$S!O;Z2aEV7Q?p!I2oiaQ~+O7vB)bD%DCq&FEs;>_71n+ z98p+`sv zuT@#-=jbbpA-uZZ6jiVIjbaBd4=w6%Xs>x<#K*#ynz}6_OSbCvJJEH5uO&s#N4nQ! zElypHcwUw-&g(?&9;O?5+t?J0ma-)g^2lXm%KOn5U8<;F;0wLoz7p+2bN-QX<%^HV zTs6<&n&N~D?C$-8y}Fly9@>TOeVJEtyat$ah3vBejb?o(wJ3;1C*$rRG!H%6HOWOZ zJ|A?zNG1u2I_gVzd=6`rGuj0ot1dptC6B&|*6Rgsa-OPt6|e;dE`^mgHS~dLs#+#5@&d{ON{S5i##uoj(e_LH|=h_W%Y0sF>b6_tP}( zw&qs}Ayv>+_Yf?K|rsJ&D?G?Ib0JKXc0aEtTO1pQf9~WJZZC`5w_1hFUn(&s; zOM88&dl{5!#71zOJU3i_+Xix4N&>W;)4ZWSkpXtS%3&86+F^rT!mts}q9bD52U+?= z%kAtIJJTrIADt{HCm=9VkWCr0KF6HQdikY1Whj^Yytd~6pUXa}NvpVU80#A%u;ugF zHOOLytRSX!f%*_%OCM*MVsko5*|9%cdqqtSKaTy@2w&I*ZQF~^#*T_abtE!5n4CUE z<2J&hSQmvH#B1RfG>Wu4b(m3i(g>!7Twec)9%#?UJEzsw|e*(iBGO$na$A*BGH zOy4!q*9Hpl8GB2e3&+9>K$xDgu)L{aBn*8VgcJ$ez~V62T*KRQ3f~+gsznYeVRHYw z-^u=;`ZwkM_oG4oc--y%_#5!k-+wQamzK-^`|ssqb*cF9{`=qYXWxJ4&PFTkXm3|- zS_h@t0(nq7oGp{x0c9SeNMvCyYxgce4|%HcO$*N#P)VsW zDjDYfQ2%vYE)8ka&izsM3UAbg$xQVIt8_K<8wDFF5Q@WmiNnO(Q^ zY^<%f+HD|byn*%tUd}>{TRZ_~t!35nk}6&=l5{Q-dJp?quk|UOP{%0@+U2FoQP1Lq zW^O!T4immw5}y$Y#0NcP@tF?7@wQw*kt3`vv;^tEGFb~C!F+vFS#{y}=DZXFsuK?? z6};}bwQ6KF$O_&j1)nW?V4BBQ4)RebctE6gx zg#uQ21cVe>R=Hs}9ueBuVjeJ#l$vtgGn2m?1EH|CxyI$rSM@4y1}ZFgT9>_XfrsZU zYGFx*GGt3Dc8}*XV9H&PMz+PFF}?J5jF>o-iej z2%zZD&fP6o2d+N`#E;c;HSS*EJ0{SFYEhjJdL8wcMLX_(>Z`{a8ICO$z1m!Oy zoZIWV1L~IlY_-p~+hh(JFSuw%5$sMN4BwGW>pvbuS3ourjq0aP+ZJ(JW;Kdn){3J( z?fhIpk0JG-Ep6V#vveNe9ns88kUc5xNO6g zK8VJbqkc+JH0)eVU4|y0HT4aV7#wX@{tcSDVLbu52iB9lZu^;8-dVIbgaz(~P!T12 zhjOYf)UGdh8ws?eonS$Xp)y$yn2PN{K|s>HBiJK%7AlK`fE@&!{lvOflL)ExQ}LAq zKFUq#NTC}Y4s$c!-U))%>c?jwFzh|XMLxcFfp_cbxo1=LdG^h?edpG281*~6MaSL& z-1;E?((;63Ctuj5i90h5>loW7<&_jf&^4r&Hbn@aT&ffB5tDXkNz)qSiCG^e@sjZ- zpuAE*JY;OOg}eL-uds@!kn9U~%PFNv@3E#NrFXi)t3P6G!LSw<8=bEiVc1<`SF(>w zcP3~9X`tgPiN=g}Ijn02lAXb9{W5kn?s<8ZzXMZc3A?Gp%SL8Nd(ffga|o8BBm-;|bs}KZUbH)B5lB*xv8o6#qXuet+Eg|G#eY z{}-26s!O5&zqnL-@c;iEf2amIAO#h9(G567*ErFlFUvXXMT0kDJK2~mJVsdw(6uEp z&?So=5*utqlaIpf)P4t+8W^IW;3pcw=;z6*?9*pdK(A?hs%Qo6(3eyhR;eaf2=Zjt z*0KP#;X_{TVwf8+uK8KYX<1JEJe9OOVWy&&!8`-%WidPOl!1R|WYgxn9Bb-5e|<=F z%$!wIYv}bg>EAg08dRO9N;hxJgqpj_>&J2D<;$}mxJBGJ zyASA%nP|klp<&=qbq+k7a-EsX%O!wWg|lc zU#tZM*(ZK`!7`OJHW$AaO-2d@Jz$g;TELrny#qh#4wL~}2N$sNP|?|0x7~#i*~1O} z0+}{AK>2Q!`usfpGd_>h*(DhH#wA=_2bt6F#p-~s)+xQUi>VusNaX0Gi*Em-g&q?A z;g&k^?Vx5!idjKpSUFgK3@eZ)X4$ib4kyFcqI!mlNfP!VEYZj*MOHt0sSw#?Qbvzi z$cyVvsZb(PT*PQL!cZ{9G}-9h;sGmMV!rFk5}jMrss?@tn?dV@#S`iFGKT_+6i5d) z8k(8asvGnPzrg?(a~sfiPXPH!u8N`;89SW^}o(qc_p z>_TJFJtLvcM3#WkTIR8HdI z>jVeYJ5S`{ld@iWS+6ktl!;>RFdP1Z>hN=SSQrlq5m-4!y&%X$fTn~L zn@8G3NgVz(BP1pR7wxMZ2a|A?Q<2_2O(iP8%{&ZpH>}QcW!Wd%5eNKE&eD(u0w85{UONfyN_z1&IoSCbZzozChq7SR_8!A|fq7DKCvEP&|QpL9)RTbJn6;vz-`F zfkH3pGoRfjH@n+==^E(ZOyo<~OqYaYzI2Us2}~$g^Zo-H%iU2tCj1%@N8~?3v>Gx# z?~XcPIgsa-O;q^O?(jA3BbPYat&zmo?%*f<7ZY>_2kK~0#{-F+1SesbW0x<=D63TC zcSoT^KX9%!9$e(zY=)m=_~NH;zkf7FH19;;fY`b*6k6WatC#Azn6m!2pb#I`rN0lq`n$W{SE6jiu#@ZMMb+%l9Ke;KI5 zLUfIrVsu=&tf}5^3mIGA3jlyw%dgWk8x=lp$0{;h9*#`nNrlfYwnDo>n zOo;xxdZ|)8=DAi$EiS?|m`AqfT7CK|<-KVsa)NG6vQ6w5XwX^xItg}p1chpluQ4r2u& zKKG_k_zwpi*p5gM2>qc@Fq+rH-k?MA1-iAx+jp^PT{5r2jq8YU6$p`E?R8M`b+T%* z&qw6f7!QUQ11G1(w;=JGtJ%px7FJ#;aqmN&W2oqec7+C`3tJUMAGNdvN4s!XZH!@g zx=u7hy!xD(M*H*hiM3FpY^!LDyHH4OuOlP!j+^VwYo_L!skvrqu92F<%L_?`4#bXUlP01f zNkn{k5l9j0;to4Ryn@_0Qk|*J7>i#HS5{MO`uMw4Jl`XUZ)q* z5l~Sg5?U3H3|X0#0m7y%-a;cC``mLA{9aImxKxmj>xeO zlO2<^$;z!~ETnz3_cV3?H>LdniSPS`(g$pPDxJ_)r`ypw_mnD|>P)WWTv^bF7;Y!C z$7J?cQhTL&64m+Ml##;|k+16K^!#FLHg0AyNO-oR!cyg_MK#XzUinzgzo=*W1yndK zm@c7St9R#!A%Qj^?3k627Y*`7joY8xEpjozTl^N4T@q=#;mj(_m$OZF`alA%4HYl6 zXxEKZ%O{5k5SC7?f9W0dASnXs2Hg=&NQBkF$|pEKG>_W^v2C@3bjyzl9)E?T;( ziwL7Vfr+g#OaahY^BQ)9A zNe!*%)K(1IFyiP0Aa(v_OjoJ@`7+}?N_2ZPEff42oKP?;3elf_sjFFwUHRq6o|&yA zWEBm4Y2?%s?J2{gwK&<#vA>G+F@;7ds zMFsX`+)|P~CJ6+eqH%#bm%}E7SYH{!<@jdSnp)X?5yyizp0!El3y}NS3)iAEa;?Ry zyyX-C45wJ|K;OWkHP-^o2ifpcwG#sULudT+rCFxhicGbCPAqdZxzN?bLL_*TiVfPL zaaU;#yD~=|ez<*wYumyC2V>6MN>}u1YSGlTy29{%)#?RiISCP2FL?x^iQ!G!JYux+ z^A=>nwn$i1o(3$KWg6ij2VdHpO~KggwAks!L$E!+_PG97>o9b@#VVW2l219C&wBT- z%;h%B#6AbXIbZh=9X?@W3kSWNokMtKU9`31q+%x(+qO?^r()Z-jfz#VZJQO_ zPQ|vZbMyUw?>6s#R%bU?XFhX{ImbKNYjfjPQG)S|q#uKuiBMX-PmRFLk=BZX(;vp4 zpddLbEWgqOodoNyLnS44*-FE?zDEeO>zE35N$tXOYIfPwXgG<|V#FN;nF3kbig;fF z*xxDA>makFR~F!LKjiVF+0LpAAhy#E9;7GRNKDAgBQhfjVo;cRMpt3QQVaJ}#&2@t z?$5Zt?$NEZl|5g2=~Bk~>_h(a584J;Uf4+Z}Yj`<@5;Y;1j8brMmP~XsM zX`M z-!}chmezE>KEvDT#C_)ldQ>_1lL=2IuEZu;n_v4o*`3Nj@6Gu3^mffNW-XDGM*KhS zoj|N6hnf~B-tq)@;Cp3c_KT|8GRrQ--<70yB+QO1pvwasZcuDd5cX~zX5(NlxF$|; zq@g;)C6AyF;f>MTvfEQ$&qo=WezIJj`<|D=>ieWYQif z=uElB9&Y3zKY6Q=sAVnQ{1`+5)Gga%7BA!Mul-`G=`LRnQIQnC1F!0+1w@PC^RDr! zN^8~e0i^lD*RCmcXeogr+2C}x+XAnv9qx`{N~otE!f&e@-6Lq^C&D{GS`J#Lx zrmn^q-_%Rit^*{qcYZ{vP&Z9nmS{AEaVs6E@h&~7xhnV5!DLU$>w|! z&@u=^9C&&Zuc<%hSRhzQ3(o;1AS>`^9)SYoW)HS<6&_4YkHT*2`?k6M1>?taqI<|#Fu?AkML0jaN+>CDiiv*hG15Cj<7y_4$eG& z`Zv}3i0TGqjz60g9)vohW3d;=;x8LIUWB&{dQ?P=E8)01)Nk ztJINc7|#ghm-;z9TU_90-=OHDBA{d%8^Xb`3w|sPj@nR!QzTMLPy7wBGMYz5mda>r zg3mbNzWsT1(w^LJoS1k5HbrJ_wu`}u?!U7f8xKkjhZX-u>3Uo&P%iRUo((TI6Yn8# zKu2Oa5w7iCB0qCfuv3kt2a~tQKw;mZ95A{LzL2jd7!DWMlr%H9&(savQS7t-2xr9k z5*Z4B42!2y+tFb(N%%&#oZGxDe$rOrWwcKnV&V1mYqA*S*T0s4_~k_{@;) zv~dIJ1@6GQAn1!$OiXT#7JNET?}K`#)nHG_Y)tUS1;jD!2LBKsk=D~WjUk9%t$QxpR6==}QY~)yO-qC8m$fX++cm-6dD&1RAJ80^ zPWgye(gi+^pJ$;fYI4B&1i2TCZ`m0!tOnjA6N;<9^Gv$ zSYXl6;NI5(v(&%#!+J(CT5p;nQU8e~(o?VusBmV;Zh~vPG;GKHH5m9KzFN60%7m=Z z*s@{yn}mSTwU_tN6lo`o2zCoL8%x|iaydRi%J6hQk<%~8iBcVFgT7?;in#}J_rmMU zib-659h|MY67vKst5Ry(V`Q3;ZobG|Nv1sati+lC+PJCBxY`AVHk_d_NOt^ZtXb5g z_{ob3|1u@nY@1y=1E4Z`PQDoFn7%6X7?*kl4*{Pg>-4D5)y_Rp}v(Okl;a$I95U* zPNTQF6H5&bq6o6@7Q!BPTk7A=6;UtCASaLcfeewCmX0?W6Lgd^ zLkf-lp3w%Xn%6#xn4gKhBU*oOA820ovIka4;*uGZC>;> zfwk#RfW#nS>#R#}j{QIyJVUQ}YS8jzHw)4`7kf$n6Sf-UYZcD-0Lo@hc6WXU<1lCHh zz3+LbBkIZn%sOyd0#xb1rvH*r%b0(mVGxXChw5Nw86$Ru5R;8aM2Pr;en1ko+mhG` zIaIIIEAZ#bFr3j2aU`|}k|ipXyxb5IwiQGh7F#_ZMF|FFTwTNS=qTp)3!NNoj7XVe z{+&-#Uo9WpUmL6TAX*Jcdd)PAWC~dZX#koSN`_uj)y%B1=2teA&QU_PmezHlqUBQ) znRMe$X=;y4D5J`Ro;=OCx~+pIhcarYCiP44y&qSRS`1!B!3gg6xZHhH%Tigr5BAvE z|3-|5d?OUB32OXCXo2{H?qsqoSl5MOUIw%YGWt0Wfe&9V|M%V0eDX&dZdfVbt;BGb z8Phy;pUH%SM9{t}Dg?E!p9tfi3mqICVGP2=G`*uM!7PN@Mp~`-&Ow!)-zceN$n?q1|7TDM9JOR19kFP4$PT4>(hSZSTg@lD?;F@E#*P zYt5WK2YMmrAxi)j>x}j~D@S=LGy~I zK`(leazGx6QNOr(t-{XQKA0otRUom>f#Kl4t!43WO1np$x@4lXy8Ur~{o8nxnmO(( zRh^Mz(i%h)_f^(wEKc;t#L1Sg8JDnvBW(}J*dB;>w6%cJ%2_23D4+gPvwA7wEbh@b zo_T|#4r$8o7tBg5V?As7 zisubAY|px?&!Xu$%uk~4{&2%^7qKOmeeo2dF+sLwqUo3WC-tnX0$3PsvJ?{NGcD#v zOW&^uw_5Ap1wiEEQ$VQl&_N0x<2l;>L!vb~E)m%9ycVBkEWUf#wO@I~O?oLh`F?kk z;*>L&w5Q>Zj`wZ+Cf7Lsv6tS;DD#&r?Jf^Leb)^qpn0=~?$bU{dSYTJ{2lO>(rd0@ zDdp+174!Jc$GlF6{)d1MqGTIHd(z?eq9~moN2Eb99~Z8_WlRD4qpL&tI(^qi&%%(B ztCy6wOxw}}e99bFFe1FDo00d(9Vwr1T>b6Mt=F^0<=;gJ%UY@4hed(ym(B%S3194v z>a=T+*qKu)?EY}_*7!6Lx#)G_To&pXNDNoY6_srxNY>gK8DpItCc)6wdjnj>1VbVC zviAx?(?wJJ!w74Sk&O}$M5`B{yKc zUoAe~qFdb8Z6m({gmjc+0?WX0pf+im*sy*+dB~pJecl&ba=ESDwGH7Xcz2feKZ(w% z0g>ir_dKhYtIs*NPmfZ!yr(#%r)R{>s24w2)ZxCx*89)sj`$qHA!oMwqai@v!oD+$ z-SjOrMV)maL(f0Rg&TwKRBbCQRQ;mE?tu@kVf;O<(ZNF-StLu{T?69 zkHuacyl4UbbLO6xwXl*pM3Vpn55z{l`X=Q7AfLK~5@Y{};^OX#2VUUI<;8`0j=%&T zL9A9TgO-72@a7-SDpI|rH;@i?D_t8dWLklQD<*PWXnQ*3UGSpjLkPJP{85I?P zD<$SoAw*glhKWhcu%B8u@QtgR>=SG{1TSW}jUBR&SpbHe{Im56CYO*MwV7z47s%Hu3+%X`Qs)E%b)>xt`DnEb=l%YY2pXw;2*;KJ6jH0;qv}lN)@zj za&QcKJZUgEJ}f7RN$d(co&~|%_u${e8Nd+1vV67>@=wdu_oN{1fVa3l%ZKk`R?eR> zJvjQ3Y$coV&~*TzsxnUTY8N$Qiz;A{UFZk%Ib`aO2(smDou<7Rir|2cBB%EGH!n_w zu3`}@%b|dS?{}Mh^8GqP!{NPQv0`1&Fn4vOf)@(EgJ9bR+S{lPE0QrHh2l~ ztS04)IK4%^fOsQBh+<$@KP@up#x8ZqW6}<_Gdk<5uRY|t@!$CStPtvZ8g=FK^GWv2 zGf%$Ey+Tm<^SAsa1e227e@f#BR~4@5!8mk3h#YUE=0CT6)a|bbZLcrGex~`4&bp$S zXnGsHogC-FceqC(i)aM_hO6F`=>{T;#* z;~@R|^0>>0=U|#=DU!mCJ41hk@{<1o$(gQXbDaKA(0bwfnA<*h+-~%)1Yh}9yapc$ zt5bs>x96oF{maj~m6#5%fwzy_2VdsKmjY*Prl0y1n8Ek{#eb}B4L^acAN*B7!et=R zIq=^y@buiWGw0JCX^-$lW(nBV$c?>~3H`$H*{f3?^46>4H4F5g*be^kp9Lbl0p-88 z{mx1Do~3IT7UjO}2+eyMmk76d!KBfGuiQ!PI4-tOF-#@rLlBk%7QK*MAg zd%OOMxK~@(G0*mJ9tGc|u+0pfyJ^8we^a3q_!;CXiU7(YJp>5{4u*WkO4PO&WBRxq z6pgp3J(!8lf&}$1otV4aT$R^Nw*dYXQ&7&_DL=MgkYOgggluEd^)qDv&vVV2dphLv!k|8r{b_98vSrZ2zr zY>zc=dgH(kJm4rLxfJc!E1VR$2(r= zvDHkv#bGQW45D~=QX^zJ)d-rl6I}BHXL0@ZO4fB0h}lVO3X(2p1X?jOLC zue85`gjVDh5Qep`k96tj8@H6j9?40;35*es&=x+PVX4DCifeR>%=l|k*I%=Lu9G+f z-R93ecHe#q`1}Hd^f=``nB1!C>ZEor3D0%KS%WV@M66b z%n+6Za*=w~JM(@vE~ekiDs5740r=F1tXIQYM1T4i!=q{J{pbvlLnu7^I#WM|46uvx zq6KnGk27jKa7$_%Y;bpc5wUUn?6g7alwLc!7TZ5LCaRre=l-Ygb~0)3u*a}!T2GDf z*-A#GFrp!@tEKnbHIfoVA^pdu|M*AB>*h;{r%9Dc)EujdD3}R$VI#|%}MwQ{oMm*C_{M5hnR}RC~ za~GaFN%DB7h}MX#NzQ;2<$FvqpA>ybW(d60!tbDvv1~_=e^!?V-s<7NZ1JJ(4O%Js zJ6(dr&eK$H41!Vj+&xxHQ~o6Mq5XdcR5>lESwe{=3?E5gVi5chi<2bHp|Rne;|oE$ zyYh)u)Wfxym6oxI+M;n5IdtyYtuMYIv)rrh-hOtsaU0?*bXOrs=>GjGxLm$? zL+6n8Est&&yLuYko+MN{o++`}(IlcXt`P1}DPkEd1`g(yvd-2sO>L%FYWyY(IkPu< zjYdB)1bF@FoJ#qk2c<}Fw=pswZk|_wa(uws=OJK<%;Df`oKyW9GVsy;gMZNf{~urX zk5n$|)X$tz10FNnL5Rv+7g>jX$|%l}-EwDhYQZf7TDB4oa(2E>dCkux+OK1HGbS@s z97#-j1D1`*&+VV>A2;rV{-^iAJcVQb^?_aAMP}D8Mhx|eKgENuGk*@lU;hhtNCOfc z0mEPYm+x~=6E-#TSq3H&yn+>er19#ZkWuG7Kc9|F%&%P$0V^x2%Nr?cJ}Xs(gzUgxKg>^rY8kKT=D380+qSyE zgg=X6I)08^*f|Euu^aSWtvIaB+Wh#nAqt*(W6aaW*nje18+8g5sN|7~C}ha4-#<_0 zb)wy;4N11T8ETwl7oi79GSavG|7N7nV;?e;eUiDUYQJWk~7bd zg{B|qJ;rFlE!)=K@U_8iLgndeKC^uDI+(7+L1fdtiK>F)IHh126wOaXOPwlF*1V@N z6nxYt)Mt~m$3>wq zv=qk3tgU4X#VUJmAFzjCE|Lzjf;!&Hmc)&hAJ4JMT{P$N6@}l<&`nKWg9?f+G~YP! zU4{(XyxAb{lC>DL+hI<%M~}GG8Nk+Uqg*H*oUM=YUC881pK82NSlCCLBN~O8=@Y>y)e&f5!Y3&-y%b!i_0sow`~b%D*D?)jogZYf6U9uIneM9 z2#|Gkg`#ZJpoqI_qPN~wnC#geqg2FN6mn_l;XGT+ACLJMR)B4k<8m1oWy0L2=FRq` z;8kgtu+^w&sUaz1nErF;i9f?9K#0&&w#|@HIA`FpFgSF+uGQ*qItP2 zmi^L@0Z1=~@V&bXiaD=LFz4N3`YAx`bwop{U#pA--2n$dE2)|4Gb05DB5>`~6#9 zavO9hQGDp$%uPss#=TEv$zw86Vw{&cX6?PcVX}>4v|E#r3_`!w{Yv<;!lJvrxB-qD z>PU-lzuCP&!~Qk1EU|8KpY=<3r>&N| zAf7;C2e5f>3Iay?-Y@Lv_`k zLXoNO&>5Yb?k)=Seh=#GKh4*@ZCOX}w^t_6B+lu(eXgs+a(a5hX6Dznm+m?*v~BI% zvuUqlq;Tn|7f;2mt3Mq$g963`j`YL|+nral`V7q>3%QmQpmK|^v03pZ zUy9kuq^KE~NG1^8v}~RWmMv2FPmKCc0VnQzRHks>^(@=FGiKmux+?me#*^g5H9O>7 z!AF+s0MiyDBTVn!F8}r8%o9DT{1RZ9>)+!~u=s5kVl)7ko_HkD%Y(l3dl2?r>Mec4 zV20yBg^##R1-)w4)f4?>9?Iml;&v%t;3qBJPunVSjUDO@0v4@bHAu*H} zP)?s(=~rA_9dS%I(!doYu=kcDFMbrN*gF+v?X-+&wr=B}vqL)WR)qFkTiZb{W(ETx zGa%uPim3h(hlc`d%?^;{&c~u8bj;;>I*&S%q>w!8%Q_UNZLnld%Hh-u>A;dQzVBc8)(FPB$F;bdMQ@@F zvi@w95yp8uRc4A2SQ&CRyg|o7@CU!^$pU_dNqKAIN;Gi!d_9$>IppM$u7SybMT2v^ z8)TAooxgy2BxPmcWhbzK;loMINkZ+J0^YS%eS0Tm;}{Igr|jV8AAYHSf2!Z-8G2#^ z6Zk>8L(tLxukgyXucS?zk2x5H&v2hfe5-o7$rkDfgGm>nbkSulV)OJ2b67TmY&3Uu z-gq+Y>V@tKDLCBiW}t7*niDS-bc`UYc1D@3*bhUhTNihcCVD_nxj7=D6*+p&Pzk*W z1H;c_eKhR-z7q`M9}5kY&A*?BR44)H5jUycIG9kdeME^JAfRRuV1a6CT+v}+VW45W zJ_E$;kYo>=mM3}kOb1j~IXtzX7MYJ;V=CMxKhEnM5|Ucu8z(kaJ+H^WRudk(s}>lx zk&pOSo66Uy^^(fIrl}ydEJ!V^MQzv=pQi{o*;SM!ebZ{f( z`l*>W+#2PuHzli|o+WWI$goC&}pT(JR&Pd!bAie-{zX8W`a=GOeHZ6U(7 zVLqH}X`}H2ZH?X)Y;h$r5YBLzg+&M-5`J5@08s4ABGTdw#zF}Xh}*#q5Z}V+uiL^f zH4(!=-)2Jzi-_BK_7m50ZL>ElKw`5@4G1-{Bjd0*H5y!#%$r2+{TB8JoM8|bS(uuX zZi}v6(@zT|>_~dFSD~f_uq_2{kiYZ;fMbckXZD#N9gLKPeG?uyfCwJ!XmCZZLMcki zIZ6t*=dx;urrNFJZKH+9PhuH&@SC~M_k`O+6`WoI!^6ka(gmdIISIZK+?WEms?9w4 zcM!o`X_mhZ`(>=y#f?&^r@Yihx`Vm6Slr?ne(N~XQ0uQ4mN3IN>HhR_pp|soSNX;87?(u4;JLZ6#eurPrF*}wetZC)Ejq9^ zWJUGx_Nh=ws`xkWd<&%!OB+(lodcdiFr^{e5u?l~yMqXHrk>-5wHx}mX*k{Ic8|v! z>EEsp$!-f_U?9Q^%mtH^^a^2^bjFXdtL4Q= z>{Jf)Cqfke|l*j9%K+~q7tHNn{%PIiTnoI8Sw4N^GM$k#x z|Mm8W%uxY#p^7!^KbJilwP2j-dK?$Z@_Ue8A?+Ypll%OAvj`fVe3Sx|%7}gpA)tPY zb`L%eca;`#?e5|((PZqfq}^sTIqQ|SXtb~Lo4KPVnIQfn5+oXZfK;7QKpyeS@q`!# z?$;DvB8g6Sd;)T|{}&o@zg@X-&<^s!89U79@(7$5XmFP+!10eViDqoBiCSFT?iq<8 zyE;SUQ2V zc@X1r&PbS90y%ZFcVft#UhYrkcxWrXinfA4aosjAM@Oz09UdI(^7y2qyoS0ONAKpr zY7CrZK@BD0<&2!kOT~Rh6eW7&C*0)xu^|sHT@37%rm2@Jeymz`mQTsF7sdJ$p9wx99 zKksmiU0{xDadMh#hR12ZkT5oj(_CZ8p;fuWUAklN6Q7Nq%y!fZpgq@q`0FQuL`pz? zu{>Es(uCBvaax8GHLD^?SG|RCF8uZB@wj#U+-TP<3zO72X@jL0<%YzJmU5H+ zr8{gI_O|6F+`%#RcAca9N!%>K5lQ$~b>o~^b!vtm+%IU zh^FH7{*wvBKdqZ?NDXrS+aDy<`P=nFc4eRf+`=aFJdW4zp0%<(v`zzop&B0d{b{YS zObT*+E308XtgDRpF?3c_;Ac~p|Mt1)-p_yAd{I;{wd1%F2%R0+GU2n}{A}s{Fyu+& zG>iOk+YUb>?J_aYTtPXh;_=ze_mZCpLmeaJJPMUuDJ9!9qe{hEFxbzJb4oK1X}#ye zRt$>;X7-!JTJ0_CF}>eJ^g1H|-gLS3ev_qBLzGEVMg6cx(MReSY7-c zRVpZhP^*fI%?l|zQKUlH*;*PVHwj8Pj6P_FjGB2C;MFP$1o|wmFuk?nHMmas{l#!214ZKZm-aV zRU{2XX*_{JMD*5)6M1_ZT%3f?Jne4xvXdbJc`}MJ;tc!o7e#wjkKU7I26f_Y+Cctw z>*eZl&h!bj!^uzjM0J#cqUAlT>ApN{hkeIsK`1XoDC5e7MTPu~C(YQvIM=$y{Vj)4 z+M1J?3cH<FBk*HxH`blYW&+5~RipP@Hs@cjUM1Be@rMBuOd`ipQa(b13?U6{pIE}3+9{J0hen7U z@TBg?L=Qod=1Cp!ds3dtjGhQiC#ETeELhE0L%f+gfo(Da-D`!cG%r)SCzc2Q$QGR z@4wKYJR?_KJHMOiFcTb$PaB?t6}GZ2tLUDq$9Vmr$r!Ms(JGyJHFRNofrQSk5BqJO zoV?ESq|(1`cRY-sl-pZ%dHMofG}m~x!L(4t=H3j^(n9)2$!{nuWqoCN?e66Fy+ki9 zhV~8GOltxGBv>I$D}lEM#BVhHTJt9^i=j-m z42i>T-sw}5JR^{{sy2##A`7oqP3-iZPuNiQ#mEwbj8~r{SU0Tr2+*HTUOcCK-&_16 z3v-2WSaBBV{U;pLsq@e`r~B2_F#gwkTP53%6z|c1n31WGJlt0IGwm1Ph*EcbqiQWs z;+MYkH6(x)`vOAoCnZxm_hp`DZR&ki40&R2Z+xx`B-j` zCq6%6G!LP{=|lKjrJpydLJj9tJ!cov?c)|1Xadif9OJ%J1FmkInGz*|xJOx_d>IGL zZ-KIQ!{<4RAiW2_>x|d05|nm8!Ko)|pN-C}ug=SE_{w#mx)iJv%^N6&AYa7R^m?!# z^xGvFQEvhE?6Cd3b5}rE-vDQ?go!*C%iJ^RNq`#nXq^CGt|+06GW~ z_2glM^ID-Wc%@g|0E2+AOW@O$vA>{QW0>eQjY)&5ydD-69wmA30Y_Yz$d8B5@0PU7 z`R3zfY3{U^DevUHaA75!l5+0ZKDIFUKE1+@T-nB%@vfz z%#8?ZFxdC;GJ}C-W@QpOcrN{Z(_$mN0M>z^4m{)jcJ)nfJC}=b4yEW5wNm}DY!eVn z?>0Q}BPT`{C8uyAM>0 zH8VrpDeU3Jv1VANqvx*3fcla`dcV})){%zcz z5$U&2+RydLJJJUgJupTE5AHUHeigh8b5W=J7=tsM0Sy5OUN(B)Yce0!c$tLUM|+M6 z4>pF_`=RdSyA~;rwjV%*0_eFU<8Tp+h;v{FVVjGT^Hkc+U;+}!1x zC#m?hC+tS?5zP5IY{Di)Q2d*^V>CE1kB(aH{p_qRY~=4kSOP5zC~zAMfpMDisLg3} zQgUVbnkeh*IBDo9_&CEk+7MVcv**Dp)`#N#GSW16 zx(zfm=P_r)4s4*hD?n%Fb@-&lPSg99Z~$HK0_Q6K!k^buqqo|d{j1h`T&x@%5xXMB5og|8e zQ8#*Je^NL*4vn-vx2eSq_5~O?SlS3atZYakOFT7!HIvdp1&$#h|7A_n;H2E!ULp5` zvz>kErGPivGq{-=32g1FX~c1e%H%pN&ehoaaV6oE*Xypl z8t2x&D!c|loVazD8lOSUf*Pxdh6Z$LICrp}36f3sgW}u3bmXw(!`qNgu!FjOp$A?p zetVN+fS~R)*RsekvFsR_c_weq64#bs*PGil+|-dOGX{fM@XT*mK(~Lh2@M}iQGcWd z4pfsD`yG*NOxhFw9bo$Fj4>+i74p{?a}g9#N0Iv;^pJD1K+r9~ElF80v>q3LxE}q3 zx$Mb^xDzwAlr4<}wS%mOSLg*cuo=0h1DPSJHiOO2n?V}Sd_E7_c^)j)&YKd`G4J{= zmGOplG`D149SLP9-?AGeSlLQ_OiQv}%8TR*X8^{Z*!&O-D)PSog~cF^Cou zI>49C{i*$Ye-jqVMKjqQOi6DygMr_>Kzg?G!*ps_E5!@AKSb5r58Bck-SH!AqDdnV z^qfstuSF~zW$#?PF>)pJlMiD>fttwy7vMCNJxVBj-qd%7 zF8puKFhcm)8I^i8TEZc;46B zRoa23O4wSA=|ny=V$9yOsDdC|0>aK>#ygJ9Aj6)7=VzQjvm_5^S{9eYoM&$pnFAf| zJz2Htu@sBIPaQ}Q#xAd2=}xA$iP$UIyr)y$fTqrIe6#w9eOeBQ!Ohbk-HNWob_MX# z+s%{%=;WXgN&tbce@Ds?pF;F-UC3<_MWbusX&^mWJ*y>-Aue}f`k1pi#k)Dwri+sI z^7-e}f%~#G57fA?+0%?i}>t13ajH>kP#FR(9$>!(Ye zFyak6x~fH;zzfjK~k!ZX@N+u%ezZJehiI^{AUD zX0{|83Z;{)HK7VxZyIg2g51t{!?lYf8$4Si+e8MmW>cT}E+zE+KK>s0 z`(BHBt)%I1{AJo=5_`uaQz(2;NcCKKWdG6{*+zM zrZ-`oHv?SIHAd^jHHr>wnEv`1Pmo8wj8T%7qCA==`G_ChFp$cl#u>z929}=Tip_sASO_*3?yeq>uSlAjndY06pkd78mRy=L^eKgAy!O_T;*%Ze z3*d8uJA!-BfpESaOPA}M^Z|wVmBqyLdO_vbO6VoNY`$#p70P%EvYGL{8jj2u6lCB`x_>z}H4WqAlyrmgRNq(QfkCYr$GX0qaT`#@scm4cVi0c&ojtYYEtS1wPw3%o!Nt!v z+p~@NdA1k8bI2*Ci={*~qpC1HQ2FS~0mdOscLk0{+vP@cFk3_6oHWJkWn+k9X`YK~ zyUm#1W`yi6qIcmUc8+xVAQS&5!JCU5;|i;4*>Y zt}fIY7x;q-=w@>$BSS-{Th*fP z$^7k>&_o?LkiU5JyGiesL|hatPjo@~MG^jl<-nYXWt7n!v{d9LR7Oh={9$Lidr-10 zYX}nWk)}aVUz!GT$gVUfxb#mQtC01hR$v7yMxX zZzmJX=O+TY1R&E1yVxbURenUw-vdRz-94z{+n~hXrKgA3Z#((%?_|0REc@Vf+g<>bm;=7Ua8q<@k2` zjxhLREf!mAa}?=qd~rhxWjHAvya{9BFL_~xf+07l(fTlF;+yQmzyH8I1gg7vAXlo@ z^G{exF;B7XcUUyTaxr)5_7{hikPaat7`#HlQ~M7C+1_MGJjeH^s+n}_dI?oq3c^8l zL2JJGpNmOgj&U95jaeZ>GzRTxA=Gewe|lDvKgUYpf28Yb()fS@=>UOOk77SPors-j z;&@ZF*wp2@d}+^*84geGpUfV-To+)1HLgqxH!ZpooWGX2 zfprIg|Bc0D@HBgGmZ@j{kbb~EVc@!SX`GEA5vYKpLo8H1R$k{^jCSL)GvxR8?uRpn zQxaSv450h+&AsO>lk*rJn_GupZxMQ&iJWy`@F{iI9g%lfM%8!Go(y7-ce3c-G*%ME zA|c5m@%vF$XJ%8bYYf7Xcbr8!O}-Yc%~2k?w$I(LRue{c%$gsDJLx`XU@`i6W&R88 z>tE$swO;zs2{^vl+*?v^FIZ~uvG;>iY0XDdP-Q1n#dTsBbaOq*iYatv2k&=1+Idy?g%8dcVi0d&Oi62ZGhWKzZY|@*PkORxqrT7B?g3gyL04u;&_tIZ(SZv_J<1PS+M^O+PDnwn?5Mj zt`OSWioJLr-*SA`aIPJDb=Pm&*svE4A3e$Y!U2I?6`XD@tt~*(3dX|wf?Q3W7|MWg zF3^@qOXw-D?yO_BG%qrLe_}u!LHsHY|8=QSEkKgwg+G>Z!D2B=e!D9+2T42|Df_++ z5Uuz4FUiBH+cB!|D-i3Kr+rq z5Vu!qCdqEm?B-_b8YLYqR`!8kt>|~@C(7!K6rt&_2j=vm8*Zz}9CQ5!4o9|~%iGGeWG z^nVp8NV|&hD0=@>DGK?{qK8-d?xp|k^;vj`4@?`4QSqFKp|dB0Jt@qTF5F%fN~ETy z;+hYv4O=)pS^V88j(g$`V+4tj0$%vwunTQf4FI;qO2>$}GY7He#@MN-4SLmUx3;`* zPPY7?!n6CT;Nra-4WZkK2req^SJ)Cfd(8Zhc;;X2*sf%iba|1|dLMlFT6&;A5lTj) zu~$5)`zAqWWC$6RA0RR>c?+YW=5CZa{h?r2{eA$TQmES6}9LFhK| zQ({gpXH~mGXp3kkFmNp)ii@MO%V})k4I2_DaE=g@A z>bBZxCI>`opOcfC(lF61+iLkl$M8y^v9W7ChLyF&*cP;#QA3QC18KqUC4TNVuOT(y_K+Q|? zC%4W(TJ{ysS&KxKq!)-9svt2HxFbZBC{;V=S0XY?gYIYkP?p|@Nmn(i7{-E2ZO<55 zAPaXJiKK~DQ+}ga?rdynFS#>RkeI&&fHlkaA5f+a1?j4;s4Ozq{e`T?#KVGv^NCI+ zL;>xP27iXfdoFVRjSlCb0mgwU5soDJC%uAhn?(A9R##w$NzsLyWXpzC%K`paAlbHLYrzxPvXUo$y zMFaMFNKZ;?J^mSi1*am`@9@ab=?*XmN}Ws$(Ye3!)giQTb|@Lw--pD|Osg|cxc$jR zucf?^mWarrC98@m>x|F8bHP2Sig@Q$ffb~R2p9-#$J}cH(>vFq=yKQG*^a(ffC~Pfy*arOk0XMH!Mg4Dey)`~njsOmWs{CcQ zPCx0R%#E5a0hUt-gQEySG3%r;QU?**HtIQ3xAv?Cvx9B3ftfXyyEVgj%q>9z4d%#M z^a8-R**DLDQ(3uWqs;RaxT?(@#ez_-5wy86&3eFS%x^XB`h$59U=W3j{3&)`9N#?t zPUfx}YM`(@22ddj!FP(Y5%}1p!%gU4h`;euM18+BQD>HR&nOW|&{IT_SzF{KYxUD7 z2*;C0$%;bt2Up*p6Iw@?i&Omoj6bIhafDhn?$^W9!*Zkg!}>KE-S6FhPU&4;Ihv6r z%au(tY%f^n28=3(PV~rKh(6@`3!9_kGuq+5!Ex+s#p3&?>6OqRm)>om8Do ztqQv93>?~FG4(~9-Q>*!Pb*c-O|?36?1`D%pfTn1OI58UGXsr6mYCl%ESBtpSDr_T zf)nTHbvk&woLq0}vdPmq3a~DkAjLKYPXO+WFTrqKNbo#B@5S(64=+0>NVRemP91H!qC*U3BEq`C)c!pY6z=tGrf#O5VMIP8d;6uH0F_D zKy>iaLjXEwrs!9l#J76Y6V^+H%o@6S*QB~5#m%u!8G z%VD;vD^YN)VD}`8)ruq0(3aNgH6ozotzOxbn)j4mEDjOtu59A2zzemfKx#*|8Ba3@ zQNok&tTA+voQ$|1Q(47cCen*LFVuGF(<+23e+idF)+s=2GOvO4bl0}vlXUh!A!}HU zg#3;e6kmIH^X!yEIdJ~V{|$ef@oO5f8%j&B+%cmKIkco`C+ZJOZkOl8;UF8b3!%k9 zXCw%UZsr)M>du-hQ=;w=$UWRjbKn_x;{l2A;BzKY@>b9Np|%S|hUBMrp-oIzlyia2 zwvR+rSI~DaJdZ!PBB8qYy1mCiF4Xor zi<#e}A25iqe&0OR@ypQ|MoqYXpbdsJOq!T1QHN4}po~#)BG|RcJU!qgAtxGz_=md9 zyrF28Is|LUWN)tj@PcM*lvN6Lang;t{-t@uh_xz8eV`w5&88V7y~7?{q*WPln(I(_ z;o?Cd=XCXHa2l&e=8VoODr%BZ{p zj#ajeBcd}QargeH(!~R~WUh6*FX;nVB05#MH;Eu%?1Szz$4zKF&X(Njz?g*}X!H?M z&J7XtX@wv3kD!U#Q)U$RCG7Ija#Fknlnve7yxrAtRlCiX7Pb6IfI2i)yVvU0DWxU3 zA#waUs|tCerfAfvOTBk9q54K*{UaqthNep$MZHfkY_xL>Nk)x}^yqeH{we-dFSv4m zixh^s=Z{fw{XPA7u72g}Vwer*(LrJSDeR5w=@y-2MSXrA`0A}lU*>tAU~iS&=0um? zZkS6#6Vfvput-6@#$cznzp)L(gVt73d1v*h@zQgq&3zDA6Ab>ngsM~RHg9ERPRq=y zQ<4Ud&#Rm_LOUBPQyrPXL&dv4l2D$*i)jXWGrpH@SXry+XC)*o5RpuxGb2w&(%IFS zh(}SIfE-40M-Cid^fgRnj@u&z4$}vCNNt@ zr6G|y`07Km%`&BfOU=n+|JH>roG4F6RfU~{7WNhxkdz;=iV4RK<1jK-Xv7e^5T3qX zOb6}z_r4A&wP=CAFMJ>x9Be_(aw8`Sb6&+;-wul3ZY_)GnirYL2m4SLR^9v zxz?UM8u_`Vbv|BPI>fi&IVfs-DGXe|ThZ_IcP18OiQlUE;0)WTE>88JH+V(LCmsbz zOb)6?-q+)f7~qDYWj3i}GJ5;3Wlm1R9#d_8y=MHa4`fn&e4aT0TKHFB-bNQ#TVN1( zI=r&G6d9uNNNC)(UCPEr8fq&oPm&su*3!s}Az{WD)Mr2ztM-p_>}71&)fT38i2Z&> z;Q@7s8j7-Or~k_oJa)aFGz9PBBp>Q0kBcm&&I-&AQJRck5Q`}RrN^B@tb!pK{Nneu zwl@^G6Z5#2RdCXKJUBweQ?^x5Qr(N2aWt`R5jb!}JH0l0jsmN_0hh5K;GZ%Sy&~xp zZ$r!;Sl|{MH-*tZTjj(4RKUf(y~;EQs~n@@LktrIXtl|V(xaZaCJ8l{g`vIZH69Nk%cYYBh?X;k zR$%s%Uzo$4u1f6dO58N!18I<9&Opf5pmDlr*L|a7^ee{JossZ{i-5YGcJnEU<4u^& zD6>pJy-;MJlG*r4lnM&WHQ$sxK>PR$UlL}s(rxPAJiC7p`6kEohS6!srF`F!e>+&A ztVG^hh3Swx>0W}cP_LfHMu!R5bu^*+xwdRbfg#n+V`a`{z`?5~ZiB&we0`|F@TsnH zaixFip>^~^Zs>J#eKz_}UA`Xe%p{6eGM5UG2Fx%3&VI+oL{iomvMWfT4X~1#F)`Kf zvx{lMmYLN(y2vxA%;=z$yVq_@sBX0eIsW0SP%JhNWTrsy9vkA&;43uQ>JZ7C7Yr9s z-KFTNq$bIxzsqNCC~9HRfv<84S`PzXg*(;aC8EpOk){)RHj{d|Wfi4I&^ zwwOKAb4bm;AtXb@&X;Pxmv`42Wo9Gl70mr|wAgd2TI9TUnWnLf+$7smZZCCf%cxa( zM-_k_B*H&jnUkeXCgy0H^7&6t5Sh&3hJRpJJ=Ky?fuc(75}L{2O?7%vn|Ve7)#kc! z8q{^5%u9RGw5uA7S-pi+%dq$u;e>Np7qZ3B_~T=Xq7Jvq*tk=(LUB9oq1_9hf1fP` z|4ClNPBYL<>b&Spek+6x0P3*^CqX+yJ9%$=qtLX^e;vZ6Nq-fpq<{U89XlMRq`&>7 zI_X~J`TV}um~al>JYJS?jwz-4?rGI)FpE)QBfWG`D=zH@W+SbBvpM$_AZQ?474g!R z^$W)*Oz`7hbX=cE4JzTeL0W&Zt42S-?6b9%Ox07;BU_5{jIqLh4VgK~+wJjarwH#l ze^4fo1fzgo&K4%Fm!dGqZfXKvhwpcteVqg?Q3=4m@4_gFHk{3M^))}JaoJdK#>%2W z$^>$BE*^9c*9pZacgm;5Q>~{Jjs#Fi;vEk4*F)qOqi$-ZC;Ebr^}HqC$!D z;MA8U8xU+_Cq@fD^cmny3w9S>Ws(lH<>hHnqJ}C)`>QV$B35GLPwPY)yI=#pc_VMQ zN~01~+$peEXKoUZ?mZ1?RI~)@eI(sCJNr-iQ=>5{v$F)u#+v}eIq|u@0XqyvISsZ+ zrTFj|g~YUxc_CAJA)nTZ38l`z8y6b9ysdV@#-13J4v)C?;{pSg%kNHCN{{11J*Jd# zN0_Z?y&_D@*{Iz+tc72*ZGs9dtu2%rEqDs51wO$R<+50OmiuBRX?((eJr18>lPK$zYeV1jILTv;dWkmS zV0PV-dW)!0sIhpO#>tkqUr1>>peg-M9>BBI<=IkQlBRVO{#yo3wy5B!m*_oLL8)p$ z2E{A>cq<15xlz(p;&m2RLKUEFrDvF;fqD9fPBo=?`f;V%W@%YtY`;?Fo=lt4PptmH z;vBJJN#Ew=^{rE^30w8;{0}{9KgH}bO;Y$|-lQ^@t_XgCDfw8Kz8oKM=DOrw6Sir{ z%wZoTD2=(7eNdg#J6l%#IGIHx0DvMN+_ZE}2dX>s%k_9S^Q`z>kGpLC`wM+FT;Y8l~U2Zd@PEz|7hc&3iO(XE3@ zhI20LB{jJ;QOp~-=dkdt)WsA@23pG~m86ScjDH^wK1>cZO=NX@C(e-rXp>a6n(NCK z^)V(|JDB$po~I+|g;xI1LY<$%jVG>vh_Q}X5whh$>lYyETf@{Bi^e7^8_n}P4AYih zC}R1}vYW}qqBPYcznikRpu_bBrn1;9E?^{h}PM7g&$z zwMwI(oSH7aD=xRgc+|_vJ@`H?vL z=@#7i6@je86FHvkLk*VU^pQ);wytr8`y&eU&ae-HPN7vbZ|w>59YAuuyPyCEby3N4(tXa%m<8vsflR77pk>(fH+!rgVLo z3jICynJUe)0L&0)qvXAgIT*X6Gh5aoV0|I!tymF6M`31P7STOA_u9lb_Cih=p-+Vr zwU9a$f*iPUOBz_|2gSJg_(1EtXwBxSF%LO1t;vKAjLeQztC4a;-w6| zp95-3+}`*kW=#3%pc5ju7RxudIaw1On{-aUT_duNrfX|Epi)hdsH(ZWs+ZdsHWqmO z7c9c1DDt%((5>r=VdD{k)2}OwVGU{Nn2U@Gsr{V4Ol zj5?%m_lvV~%sY}|P(P3sQ}W0?q=liRJK-oQ^)-vppO0~jYndPAcxWuN)kFW*z$EqD zT$yl^Mm`H~E698$UX1PY12__Ukr^?i1|NP!=;O`b_r zyKBzS^sM9NO!u_1hp##t1>&{?b%g~}ZmTAJrmBx(^DfNoFK(Y3Zp&y-Wlnd6rH#E*EDzs;GLnwqmzD)cy}+nA6M2P+|986*r%! zi^|U6@8?+J9)xQhepmNGIhv$w+X&Ue?~0vwi)?of3ONllcT)=kidivNF{P6NgEt}C zWhYoXt1-1ae@P`5?XkCNImAC<)RzXM=_r=6{@O8v()WwwmEw7Kv9SR3Dx)-%psZoI z)ue9O(sj94j=UKu1?PPL%9(RP3e+Tr$2gA-^Lnj)_6j!6MeDTQU0qK4vB%e+C(7Rz z;Huj~vjrk+z1zbP9zSt6$IM@8eNS!M+A`!>B3Yx4t{m>GvkzQhx_{{82S9i~Zr;2e zsKoeBgm_8%4UrM@o9q8j$o)reV~_s7dfO~?+YyqC*aJ6_Ltk827Xd#c<4}tK&{_Yz z*#A~<6R24EZzlL`{7Vf-f&KRU1_4wpt2 zq9Ob>=y*Mg3S!ni%5sGuFCC$yH>c2JKNB_66F7QJ@)?6!g6br^f4<{Js(Y);!evmF zjP)Nbn0sOj>>tbuFL#dgaC;2CmbSKaCY%XQ!RTrMa6k&r+A(Gq5DVF7{k_=&m|H#k zwa_+hBr*@~i$8~Rk$M@gt0TT>67HsEuk7vhAh_z>J6T}j;Ldqj< z5sv__O9YbvS8v*`K&kYuA1M0OZZR5_7YBb>)_s zEh88IP4;cB$MStWTYoY?nSD!SSukkvA_cu(t?iTQ$h+u(4bML)YhgaP0PVq&t^2X) zs2JyD5dX60%_3g$Gp0!R#THcC_(!$M1B+$Syay5ZD?!O6xX68RE?)S-8O$HNNF8Ys z7NgDZ7mm`yl+lD6(`(gjYETx+QYZ9#(-6{&&t@aG2w#l4QIsNLBlbR~s|80om)9Ar zb|5yf_A_zd6t(@Hq(pp_e0_u3Do@P=_*0FH?I&-JoQc}A!a`iEDOI8Y(1wnHWo{;=K>>qE7~f*4ci>}_j` zU`BC*-8}dqQ1W;SC4R@t?akmea9X*ai^0^W>54-ydRU>xL+tImaJp~L8CCF1`UP*j za{8IPMWc1IyqW-8*PuUDQQvPle#lA=!bV9f_4R<_z~6|czsJ89TVKz3J0fxTWmKc(e;sK~Eb9BBwmprA@X+J>$3%>|=a9^THf%H^+H=fhTEklPk3` zShFG_hDX)Ls6qNQ@S6UKR}Y~W153u&FWEW+2Lok;SI9_xg=uLEp6)5$%bff0o_&yQ zeS5_;c$IY3&aR?b`5C^;JvUb`34iFW)0(zVu4hjTfmRZ?6g1ARU%9>yOU_2GS?)Bl zuAwWcQ?dt_n3wv1cI;Mc7ieJ|kf(813Hx?BI=J)S=!QbsU$$zwC@pIhSOnTQk3#Vi zua~)ofC}x=%idiOO5U?}?Fib*NO4_;@eBocW7IZaAJ3lWd`F(-=XtRT!?Mo?4^IS zU@>gxG0ckdz)0=uIM>~J)TIk;B$?2&Gaq*f?>-Q^#^kOy306eJJ4d7yHXa*3 z!}9CFQ(%I&klJ5s)lQN33{=mk`hcC7AsgC~jBNRmVTByqvAD8m37Cy}Jit)`E?vo4 zJgl}4s%@9dMu?U#{v3vNeM_Rw%;gm8#;CL&vWo7BK|ehLrCmMSC^(urPZ4iWMUji8 z`_@7#|LKZb9R5aq1eT{FJ(<24hx>?7iU^WkWc#tUo&D81*@iiJw#Kc0BwZ@_9Ec*y zpXaIY(2EQGePQRbgxGI87&4`55x&!tzGfsBBFk~Kf-OOR|4E{Fv92`tW ztu0?f?N$>WrjPLj#+M{efc|$z4K4}Y4>(!~XmGRkXo}DJz*rE&6Ub)b$>!JfpzT}n zr;k{Oq}`@^C!b%yxS3^ z4eVa;Lr2aPn(wXCdB_dD#Y~Sxf>?LPiGjT2z4cPg9!$6%>>uQ=ql0qZB2`RRx&7a_ ze~urK9_2->lj#*tbpDn2jJkZ3{`-MPbr^r$(8KXM$l+=`g@=?v6tV(THE-zeS3z3N zAAC3^relH$75LBscuHKit7XMfK>^i=SGmIc`;m)SscgM8=B^wOAr$xda# zJMbe5t>zC%l9JulISYV%^ z_oB<4wFd^!t=uw?Il0UE@agQJfXMFJqQ0_%*`&Qen%McUW86w1OR%e9+@^N10NFTvU<-9ld@h$ z#&joZJIZ(^F+m07QvEcye#w)wc@Mdz8m!juD%RjwwJrEsdo0RK)vWhdbiB?w@B+J6Ogg`v9Ku0?VjV;YX}?=!0a%MOL^&K1gR@j#ciJHsMl+xby2MQ zKjFwc4_3}@{wDn63WRI0e)~H=^f#9+l`lUdb-ZrQNKI$0RU2D^wIA&0f!O67u{F&T z*{9)3ROLN(mV%oLS{C7Gos#DLNt~(SV_%fc`9DF`9tR-D0;hw3-sVV4mGM-}uc=^+ zK-DemTPq<9VIBwiN~@qEO|*i_fADmkGMZf8erWrDzect5^W$7EX!HhwyB^yyn;ljl zD(KaSJjsasFd`PA2hyWzFCjQ%4xN;wU@x9uvskrp_0Nv<@hltiea_S9pP9_QalQIRJz|t9rSJ0O)$ikr`tf#CCh=OI5r0C4tof3Ctc|XS^Y1e zRJmvpZdOln8qgcyS5hh-V03uTYtU=!WgERiiqSS>N_8qjZp*2EH+aV_M#xjetV zAeEETyL-pv>xUk=^HG#eG*EopOO4H}rkRHxO>h%;3p1swH4c#m1cONlDXj~q`I^Gx zK%4?DR+w7PNDQvz60ek|6`E-K@nW%z_~RxX8rdUjbKR#BUVQD?62+)c!lgC0s?F_W z1;Ry!C&BdMjdW^SGrP5YFcH*=aYCE!BAb&;Z4VwJX2EMNSx)2El0CL#Fmxqq>g#E1 zY?>C0RT{p9AZ^*+q@&KggR__-UzbG$S9G5kRK=`ov;Sc|)#5?}y?e?3mj(2H($dUUjmi_~-q zCzRY>*zsb^Dys9wm556o%8>Ix^Ho6n(e!X$!hUq85fO1ioBL9u#@8HLHlxmR;s_IV z^s?BYP)p+QTf{1D8^F@?8lzLPT+oxOd;tCTh=b64n`bC=F6Rx5&oOFA>WXgmG%PCO zFnE4@kFez>E*Btq-^ms_>Ipa>UZ!nJLar|}H-B3(v0}hdSdMoXCNwSStZ88g48WfV zVKxvR6@DfzR9}&0S*YTtHKLe5(2r!Snw>v=WY3$3ih|ofE_u)Pt6LnenA9tHf3E#| z8CA$itnJSq5H}Sqc7pb~1bnNdlvsQnMV4|~_@3BSd`?^rq`pdwt@xYtd%#6HH79R6 z!u8DOB0Kp|U_QeHDA|r@&QN1wXcmlDU;^n2N1XdtmE4@|I)esQn~1q@-l;x4ELl5ZJZkm@bw`&ln337%Xvi#R_XhP@ zFq~YedK2O`F$K3T7>_lqhyq*S05JJ%b)UV4P>FrumXh z*NrShtn)ZDPa;u30l$E~*S0lweKDEDm;jXINZuf(+nXCZj9>0!s6aEEy;6*#{G9-^DymbKVf_lUgNwaXt84wamd zKfbWSqBQo4mF2rS(`h@5r&;3S5jK!y98RByXGu6m6Z(nOUPELZUMp+f)w3JBdc%B5TZEn=pl;lHodryH~9@1l_`;EQGf2!{#?sa~4IpFkc z_S)8{of{Kwt!fW<##7@NN8?O%-StVY^2^v3qK4d#jS9X-c5T3XdbG8E1eYC-ASmL? zzVf&?*P!~oh)+nE*^yekZx0FqHc6Q~6MaD5xt*5g;9c%}o1i_n&Vx134j}B6!a$XM z9YF9EX;2kHl03o_>XI` zmj4P14fg~5=LPim=F^hAWQTUd&jnNQ+D7(ur-fX+#Yl;-*_|)kIh{nYPt8}mKBRm9 zn6O=aZPNsaButDLk50~hb0yRcWIsQ$1!&{RAcv2_pMP{g`DyAgUf?hZ&1l=<{PEjo zmvXZ*u5gAi++FsXvRKPGA@P28^a|M-&qf zi*4s;O(Pu2Jf=;f%%ESB@8V}=zS7lIe7vK1|EHG`;};LjOtmj^yV5@(v&#Y zsdJ+1%_s6etK3$SeQaRND<96K+peN?U0jUIg0R2{n9V&2BrKS=RI$P2ei?cINQHX{ zTS7Gpw-M0~$KpQ+Y0odzdIqg9y(f7bonnhVA=KACX!sG;e##Ia(+xJJyj?CCvZT}1 z-;uxHF8S~yEL$ypTV7fIVas}(ew?fVJnH;Bwk$qVel}f8K2X))lz|0WIYG`zUpD>c z-8c43uC%`v#|p#g&u$yuO(8tO6R}+@dUy1_5qEuNCEP@Bar@Jq3!F1S)Tk?C%DqGF zkPzPYSACPgeZFTqJ;;1FweIT;*nUX)*CN&`%U?@~B<|P3D?%}8q(RD6v(FPu!3en@ zC)$bP7Qb>vPD&rtE5$ba1}9-=AM?Wlr{N@uqX(P&mc13&QM+c*16rq%#07&<{Jpgn zr_S|Wh_|Bq+E;wxc&T&Q1n~hkm#nbW7~D~3_J)QYpD2}DH5k7Turq%8wj-XDEItH! zO3brSIyOZ(B@;10|G*PDhW6m`8e?}6z#I~&A7$wtRyJtX z<3aWkHIm$csU(&4v`K8wOojUP$g20x#-jOn_ZT@oggxOt7(K9&83wP}UUI8!A@s;y zSBu(Hq;u4HDJf180=mqgtJ=@fS&#SD+u zRB#>AUNp|_sth%%)gUE>;VY3uDdriG;aieG;lT18rb-KAV5Pf=YS(INmMw{+=R+W_ zAC}ZShsqWV-9~i;jpK)Nb7G?uURWf{-bR@d%^+5f_m3K~ygG)`Eo^Ev462WURb)6o z%ududW_*l3=jPSa2m>%u2_J>1_PgdVl|9t#L^^(>17nj@upbpD` zo};}=Dlrx0ciD(mpdyA?GC>xdP4b7}kr2kwnJJ$l1MbY-7CFx&EG#c-^7%e!%_sQO z7fcp)NfON3OzbK883Eg9%8IefnnGw_TKJN%8m;NvrED`Oi-xA7$ZKP8C6-+?TQLW zib!^u?I8}S~;ykPCM3%+^C)jP$u**-d0 z;X)V2b4cO<@4P{pf&ZJ9tS13wQ9IWVlwUioolN75mWj)qAkON&@At7r7BVnq=$74T zV#=*QV+nSwI!%Z6pvVW~YyJTRioW4u!$Pw#kEr=^^9v)Q&oKCI8ou$|e@&grkWh@- zGUxjCPO;4ZLbJBQMvOa_rftBTFaBCoMwvvb_2`JFwViMFu zQd>K(TGd~wD;kppqA5k718?Xw>VH`{SY6{_+)Jd>!;3!_w4S7XgVuALZOV))r&RZ} zx+&jo4PD9ZdHTc!XiAeoSso}LFxqY84Kxhkln_Tm3$s^=dH$3|ayaJHgs2-b%nQbF z-G}lyP;odO2h}F@7??oFL|7^PRKL6r#@m_6sbxQD}6;b3Lj%L&v8YVm1W?nOm zo>H;n#M+4i=ZK@`)vlTDKhX&&uVgNr1QISSxgm0}r-G#V!;eAL`IVe|d1X$ZDb7q) zu*%tEoQmDk)rX_2ZZ6V1?m*}_X-Dw4rvs3P91ZCRUQ-)UXvg5o2gkpjz8aPJ7eZoT zjJb)4vVOc**QnFCQ5{kdVuA-FJ#^nlxknO?coRE{X(|e`20CL57j0WVDj__qZCA~) zm&@ZQsQ+4d3fQPy9|EumCRuqktG-pqVF}t$OakV-%oJubKY+ZHltVl*lL&~cWjBb; zWNi^7ZzX)-n#jW)0Y#Zn*&U?}1uLfqm({&wr~X z+2CW4^pf%JZ410V?RaQztC!$S9HqmRn6fy%ufcB$j$?_xIL&kx zSkEc_#{Ap54U)dN5=Y`Ssda}Y?m}*=s|F{8FcJ*9*_&4yrLEwKMW~dX8{*2`VJBHz z25_wX9Uv_HS{;*(y@S~I2Td=GG9mAGzcI6V2@7UGb`@{JD1{hX#ujTLV|{#s|FV-X zhL$q7;(;|WuhjUw6s&YXCKJD@Ic#lloSDO@p}nhIz{rb?C*8DP{PZ8a-1xTL1tQAp zoQlc6B@1}gPx=YJZbTl+bQ@_?WR`HisY8|(*E)|O%ei`k(`UEcv_JR5eeIF072OV}$vZ7vCrG}X#om4K`n-M}w-(Q$CUsei+q4+K2Yh^jpnrt4 zqLYi{vZ3*U=IE{|8Dd-4#v2?>DG5y0))C)&;wtVS|k`|s+*17v#D#2A>OrG)l zJWWXF2-NmlcKs=X+=W9hY9lc7I~1ebQ1@oH2ou-fHz;cG1oQXpnT0KAxr3+xk%#kY()MBdI|Kjq&qnkxYdPXTnicK|!H z1zN^og3(Qu;=vEf=QRer4nM!gjt0qZSmIdIlF)>&)6N7m)}USgh^-RW82>w^atZ-w zUc4?ncCDwYO;Dn`@f17^@>t@ZL=M+<&0V&2Jh+m{%i-Ciwg(R6UYyfa*>;%q4uOu> z1DCC{7&YEBs_c%rDQ-D^t*Yy1TRX%_ASRHiGafhyIkjvsLoeP|>=-hIr}UOQ+~j6B z{tS1<3mMfo5ud{$79HAa@U}Si^Q;;3t(Y}R-f&sKTTPvoFpeu={J=mUh7ti;#S^{l z0=5L)qxe+8@6G#=U&9LAn#Bg%L_TT->uETUD#CG!*B3Y+3*WK8Bd~U|0Dl4}b*OBg z;@dG{A8%Pz1k)i8w~*G7k=DTh-e+eYK7*Bsh*?=e(AwB2bA@77+C<sPAtIWujpp!I=QEo?CZb&W0SUX5Ti-Niu}5e)Q&w|Js>wQf(q zxhad}0#dZ`w=q7q{gi@wW~$c0iiU+cHyWNoLM`Lq~P3=hGMU~&h^HK zzbiscWD3RY081E_+sVrIx&N`F0TZ>pj}03|4iDC?@39K4#(}FN1r3eAvr! z1x{-0Fgm12;N7iv!4cXfC}q70R=PtojO0=9w%yMJ%4yg8d4&jsW8F&4PgH?G+@yw#1GbrJHCIlQsDTVIE!y&P&*T*N=4ihvU$l(>LD8aUrX^Q? zyK;_=MSVB{iBwijmOE;R-W8RS1Erx|wcf^)<;<0PYb~a9%A=!qsCS=3H+JJNH-yx5 zAe@aOp8L*}t3H(G?^|?P)DTKZdSx-sND?l;W5y&udn5hFfLDe43xS53^duBTl%_tjQ397n}vx zZ#5Ld{`sTWO?iGzKKBBCOW!SRF5f`FQqpT>fU)>SsGSEc_d(%y<=OT;iD%7xY7N4q zS_Q%)C{B&lo9~%U)j5tt>i#G6D{Cs~SnZ8b$krEy_B7BI3A>}QdbNTZ&(2NFcvn+u ziLqN{Wvvk-b-5bZ7p>#*?N-?_Dg5&Qu|F$#-!oChEdJ#PfDnqC+ ztN77qy^UiAB`C5va0X5SE1MDfbNvY8okXuKwl`Bq_@PKAu3dlQ!d#(L4n>E-0|u_3?wn7VD3Ap{aTmF1^j(+$z zD~w=rG0ZJRCGE8C%pwcEFO#DrR?~YwjC+TJBEQRTN=pN_P(3bGMw~%GN2yBkfCCU4 zqbu{Sr4bB1d^aJ?YP%*QW4}awzU>h#f3h{}HdvJ7AVlgv==*obMfw9h<{>2B{W_N= zwH4(z0ZjE>Ve0TsCZnguEx^o zM+ed-*3V_+W0^BU?0`bqM-*}MBWX-P`JKWZz4qgo+%$heFxcn(w9(C<|r@yKdr2) z4IM+4)fCHIGS=J*Z{JML_KY}EBd49LwEQQ+)P=e@l54?iq4=u7nxL2A9ZZTm!^e5- zTlX9Ij!~R;G!4D}$dr_)K%C7kg?tLDx~1UmZ-4Ys;4L>PZV)_iCoB&}ECYdKO)+Q*-8$eO-(N340&WNoTe7%M`s zQ2T2peCY)1RCV?fXSk#q4m<`u=+K%2YJV8g4S1MpehQJ ze~?ktHP>$H_Cle-EN|jFaHLNH-${BD}h8CGtpT&Ui z?MAd-$bWv!A_%!VO9JXuT#8po|UDOBBFH+SV;D_2nva)GGueVs`;weO`XRHD)p?QeV@ zbZY1{gzxGO`n4f@QfW+!%^Xq%3);*5;_U<3t!P>r&$rboy~E>K$Ob^b?~atyr`zd; zyAIx*X-PM7qLnyQ24bBW9W!9%sb}HWe(4!hDgt+Vxi#RyOeq^Pj82dgg)WcLay};E zPrdh;6^IfUcTZUicYSxt?ed!UD=q=D9o-+p)KB~Rogpgthoxm+ zQQ$;RX`zR?>_KW9L%xNQrBy7mcvDAitjIh+t7@Kwxo@VZ-H}fkdm688v8>eevDX`D zF>=Ezf#mSFoyo`4;ohZN@q;PY+lX`Cg)%<4OPY2C@70t_k&Jb1w>d*eiTL%Q14qZQ_Cfl~Hx2IzFYB_zqopL0VQG-nmMaVv(_pxr~zb=o0wGE>dR0n+ZFB$-4?OqS1U?K+{!=%}uR`;*naOF0MBraveQ zG1fz%Tk*!OCx0getc~&APeS7>%mP#tOtm5PRR^%t+ zfpJ(0v(dF$Viv0RU-isl!T0PSo+i~24e}960=`ZTssr5Z99EDi+r4;FjwtZCOxw3ZJfeR^ih!QZ5;G*N56+ zQE`nyh%9Ac(dOxC>KBto2J*$Ct>UOy*_V+C7I*gbAU-3pBQ_(R>Um-~cv{_)-MEo+ z_CixIJG$Fjl2+sD`KcHYRJzA31!i2PxAq!aqCjkZ;O_BqV0$)7V9X8$M%HziKV?RA z^;UNmX^L@tPpf(s|G=!)4F>JS_gjYG^yl0@^Q=k|QvmT_pw#KIh;i6QX$#Q5@I&<< zu?*fOVy=|RbF7~h5cz4E5=L)^CP(_I~NG;I%00$1f!*C&-UQ8BJ ziI*|7lXMRIC9w~t>ljumdn7kTA}+JcF75RD$380*r-GWQjm*AsAvA*G&w3ERzxTg364vIn!s3L^r8NvUiu6J zU!GYYmKQ-@4byj1n&=4nU;hPeK#{*v2#Kb)u0WM`f0$*V&>f}pmFm`!dJV4z$I0b~ zB&=1Tob$^mZAGjbK@@bQ4W8BTA#^!`gl7OPRC(ARAngz`8vG1d+q#s!@iT8F7Q-}s z!=ve!e2Sf^-$MkW>GCiakQ9ErvOnI+y)IT##{87PGJF zrpdH*mUnf96iv*=p#D%oA%v&SUCGt`u%JaZGO=`#>AdohzC3cL@~U3M)PL|HHoE4i zM`{4_Z9XMm$=fmn3}5k1nuLG}u)H&5_|!a<6b37wS#y}b(QCiE7hHdmd{?xh+0DIs z(T${3#+ZU?C+j!o0%Ud}>>Pu_7juW@+@i~03K|KgM~TsJEZCsh^9`w8Fd!~e#AL}) zwU<05b=R{*WzJFEU+S=|6`>DMr4W=9Z%fMiU%r4-b@Ox5CFT@zIq3}^X=kM!7|90u zZrPVt;p8ZUPUG?gq{SjDl#`i!$Vgi^sY&X%%#! zuPDH4de3>fUqVzB{5aPOI=5-&L;~D?S(4R90c_Zs>V#Xs+j%cQ(1|gWk|X-oGw||7}ix!_TOC{b4^nZ?Uno5IO5W zgBZhFi8eQUJ?mZGS+A3_?wA)}Pk~qD8NQX1-~1c+gkUb(+1!!~fn$^FMKC<0ObNK+ zGS5fKWw6&};K=c!tue!RdAGC)5*Q;6n^B#R7yTiuu{qBA*#_0Tn%BP>a^{p@VJPp^ znR7Q|AJ`WkT=^rNg>JGAb=jBf?n3Q&eW>h*QWp@?enh=X8D{(Y&%`kqYeaS}Gis^9 zeeoE{P-sx2W@61BsIfeJ2=BoY_CVe}X!aj;6{pTNLy$d5>MuW$%{Mf>crX}Uwvs>Q z+xaiZdM>LmycgOntK;%p-ZTr5%B=@cBaLpWukaa;oXeR6%x~~I#VXxK?hEccW+hwshH3MvvsA5k9q)ak=HjJKf)lexAHJ8*TK+fp zj8$zcOu1Qh^_y5<#S7jI*Z|W^t}#J7Zt4kbsM)6f{3k>0880uQvx7PnbP3Nx8FVof zB&1{~1zY@iS&b3kU;4PijT}yPc}04LD3g9ynprlsA*i2aNH~JfAAST8(qgv7k}WC^ zVFkDO%qcl=Iq1OQd9H<1lmhhr$CXURu)`(}QD%HG&!oX?wL76WXXPM*=aM;-$^gDJ zkxj$ZB(1bumqgx7^VXVCFAHkm=inL9=VE;GSuSo;C(PY6FS|wSii4uRMU7||Z(aVM z$Y31#K;nw!L5uCL^4mEZKi$OgZtU=R=&p|AM-J!Ab>Ongt*r$Qr_Qk+a%#zCt_^PC z@_I0M^KUX4#)HBmJ$~EuT(*7Ik9m1Gry>{)Fryq#dpA(#3h_@et(%9XN@uX1lb5U~U}+zUB(7uTo=It7OE?J*@-m)IeL;d7C@OJ=Y1hx%aDJG#G6H^to@ z4^LirNUzfUoUQ?#M+ALGd?7+Pr7y%2-SD)=92FY~0)FCiND(k$o zle7Mi`KUE4GFX^DySXQOVXog~h-U(P?g&;Kr65P(6EFKhMC7k=0ZXag#>MsQvDbO+ zI;;s2O8ha*k&>6X>l%N??6!D3F5+{g7i!ON?u?NEWh1{6c#Ny+p>-5txRZ_Rn7F+3B~OPpcoJd?OGl^?zDe4!Zi(7a*V zpVYyh;aryjP`KBu&_=FrJ2P9?I__byBtq0+o;9hfK}QQ3QOST+2OY(1y7g+(-=0Veg4 zh&0nA<*>?nQ$M9*(3IK5kaJ6|I+kla$5kG5D&s52B9B|Ve(vnk83ZS&A;bTWFZHvuUQ&HrWx|>4dc}Zvv zQ>=DZe~1>EqnM9{Nl7710 z`ZF^LL`D!65xzZ%f!2UPJmLAD(X)L$iMXF)+yr~V;}Y!^$;V)rX+#~0(m~{EY%F@@ zS`K!e1!;%75$%c*^>Rci*Ww8%F_)~OidXK;&Do~<9SXey!rb1Zj|;f`UBW1QYtGe zXk@zns+#IRCNiU^?D^UA=_fsGiI32ypt9nVguW?}5~(JJ$>@gyxPONJO0hh&RS_j^Sb#OA6kv7h=pn`;!vwWq6l(v_U@k+Y*YL~cJ-Ib`*z~>C^u5*a9<%8C zKVB)Ig)dvXz=obVMqL!d9F^N1xQ!APM#_k zTz7uM-ckN&6>ouhlqlx2!kBJ(!3Mz;jL+Fc?_0K02235Hh6kbMe7(yMAYpq+$=HVl zuU9-k@r!-$a{mQ)Y|c98>{<}!*`yo=>2dE5jcT#P_!Vr%{PAGffypp~=GUa!2|j~^ z)y%4@*QPRg&=bH`3(q(}YZlkH*3%^x8KGl`q3{%>J`<<$i7x`#yJg_igek<=hG^H! zh;JLnq@ITI3k$$9g{NsgYwG*_hT7dX=}-NDmd(B_j@ihKpHn?Ep1~cx;vR#+CB$Y3 z#AZz_B@VHv{0_PGP6S3$L3I>GO7x3%VWa9HUPscdLt%jp^=DHR*1;1t@dO{3Ic!(} z$yfu#M%{k;e>3{I=J7c;qcbsZ&u4%{HbAd z3&mT;li9GW)vS|!%?%lB_zh@270!JnVp6TUbo#^2VAiFpbik_dw8#5i7{v29joJy= zPir)q?pn0I&Sf33@x#tTF0GhE?1R zOD{mB2_2JGIUxIL1L<@rE)mpmGQJ9Z5`<#a{zfEqb<9jSD)G%_;z(o}J{*i-S}|N)ys5b8kgYV$aP^f8Y#7kOSx`ihkHNdiBK@lB zZ>X5BE0CPrxlQ#G#a#4Loi1kjFq5YQf)^t|Ew2qAV=41}WbJESMZR3=ep*{JmfpX}a7<>3qc=w^ zwVDW`fsK;2-VM84+r8)u8y%~x-~jibDv2FsY4=RwDNJJDo+?vc+C| zXxEpzHE;RInx2vQ)wrbxKAVx1)}THMzod=7Y!w<*NSMu-EEt^HTB?Ie>Kk248QiS4 zoE?}AOG^nCU9KMAyCsEY&G4K%vVUW>q%U@Lu4(V^yeMiS%Zt2@-O>KriVd3)V}Xk==q`${N{Mz4TQtebr0mb}2iTLSNC= z)B7S?fSso29^Y$4MsV!DXceaM=80pm@_HE{e@0=^J%RErKju+0oWk57M|MdVMiKOQ zHa*wEyh?=BOkv(WDUGKE*BC^1qHNUg<_o?l^wN2xX>n+ib%B_OP`-&e=rfNhx_OeF z;j#=qaQyn{^$%4$8HDeTN5dX;I3;Hpu0*@Gu%6oP z|H(F+-JhF0;Asi<&4PkO|;tb~96-EY~Z#~a-ZJ5q7xmVUWqxr@jj$ZF38@2Ge#thW*6pPsx zTlu-7rEEbKRaYWMbSyEFIfs%91T>o@Fh4MwbWh5Wb)X+BjswtQl=gBNM^yG0v%UXj&YBaxoD)cFa!*F!uS^>A zZ2R>PHSQv82=@c?7peetF!#o&^ws`V`PW>NKm^%ly8;4^T%APLeIx3}mrwibndYn! zCIX*$z(vh-s^;~P*dwEb7Y1G8u4<9P@9iyRwQoJhs zdAc#9WcVi$&Yo%RrI&7{QEQep!OO1m(U{RTZxk^MAC&SB%#-vWPbD;w(xO2^xNS^XcYx1Wtgk z`E+xe0_R>po)blqkrgMhTX4E7JjsB2m@#37zFFVLjl+4Io>!{!ss5$+l6CBp;)!b_ zVv|o@KOGGz5_gzjl?xGA8{$y;n#=Sxmub#iro5yG3K{2nAr&b*!K=k_-)rb7eS58> zfO{5fE_yY$8s`=W0T{BmfAp9-xxr9!7PM7R&}Y`+xJ{m>O`b+Bc~*gH5qVZIB}x^2 zF=-{Yk`~*7Ezj(pK`vEEc5__1qlLG4}c@VW$SC z0L`5rGqj@31I^dQo!YN~yZYwcZtJs+X3WYdYc*>&yG&03oQA%1o*WxHJ1(4z?1ET2 z&#phmIlEf(d^wT(;XIDPRkyrH`=ZhW1a~sS=57-Og2kOTauXJyEj8_8Wd5*DK>{P; zpvIP|2-W}O_$@N*t-=I^fGseF-RCUO$O_4Kj6reuWXy-BUG^ZFbM4%-3}~CcRP0=* zZkats$F*ida9a_PZg-|N6MV5~^Hs%z&!^%Sm(k@t_r)>upHXbPE~G=F+wWMI>apYv zzTCwzNvEtoAum9qaETSJFC&h8S#rYM^}E3v3ky?8OhH|p;`s!&a4SvH6$n$$OqUm? z9&EjV~rhTCU^O2TA++bm`I2+N9+0iZ)g36mvOI&NMhN ztt>j}-zAdt(IX7{eR=r&y%zFo(Lz;#H-?Bs-OY;d{H6(67G4P)bQYLCClN60fRwA| zuO8qku34Z6?x>S~vhM}C(TtaHFD9w}isl0Bq+X{Vnt)}3YaOSdGA=9@5@w)g^GU)m zLFHj4gOTj0ayNF@x59IL8!HX-6(#pKlpUEL>ANu-_WzhAt&I1qQ*om}z7giDS@7A{ z0I&#N+h12aWkeDqk`cuKeVaRx>+IrETR;T~3J+6f3kt2!nlHFFCvy7B4w1GLRVj0E zMWNBzC>5KEp&`*$AM+^9tQcvctupJ1?i0Gp&}oYbD-4}3n1z^9Pd_R2EX;oUy<(;) zF^!m$sDz5t43NE{I}f>R;ubfCTtB!MJ&5qXD0+K*`2ErU&)&PYw~ZT%!{_gO3dZfv zD}w=f)pt$-n7Sl+Kos8 zgTY`h7z_q8e+gc^e181$?VG3XUmhNbj~l*hJ@U2`rR;e}Qb>1E+9)Zru~C?|hdZHeXzdr?(aL4u(K;_(Y-Rin_L5y2 z3spqu95u5%A}m(PI!;%g40xi=BtxjFF2HcuiUeZ zKaTycRU$&=j#HfS&Y3#>)C#HP>Su=H*H70D&^Fbmb2K-Jc}Z7k<2av;Bpc_s&>WUO zJA`KaI?W7E6)ar*bT_yoZCXUnhYy%k?^tN)DNXrRX$|>FB z#yx!-rIdVyYFx_iy9-)Q=b`JN|9BpO3mMy@?0a4%8pX^sGi%iiXum5hx$5_r+ij;1(BK(^Apz>P7Z4>Y~T?z>}7$yf~I*befMP zW#IF?=RACM@mGPH6j%+Xv@2#>TQO1d9g`+s`nQ}DoJkK{`UST?ux4_mImySU*fThR zBJ#6TkuhO%77htZcWp0R)fecAr%FFX)yeFUZHeaZ9?;c05!QZ>PZa4ODyK&!oeLm;HjCh{HKu6s3I`YAq#yarTV;r;P8zi&uC!RW=Yjag ziaQpQi<(l@dFfIm`TSRZar4ir54p=0u+I5>$n$+suH?206txT!ZQWF;5oj%#_w01W z$cy;_EMakG?|<$Cf73@}=~qEp98u<-;gY@$H}KZ|q8UU!mGO8w%OX*;a33bO|4^zj zLQ*3VNI`4M#E2p6YoTQ7ep)j{@tRZHY&^}FpIO|?S&V3_O(ZpXP$)ce!cfoaBHs|$ z2C&TrExJ+481TIW6u?)8am1alRhF4bv|O!C zNAF<&pChh4Gu&Ce9F9Z>W|q}Nl%BTYOTlNzD`W2N6)6z;4Kf`_NV?&YDhS#NmQ7Qq zSI%}$Y=F%ux7YQ%=;0RIg|DjY&ePl3?b=kdDA;JXgl~yJAd#jVi)vR!!+%O>=nV2+19++KLT3YB$Bt zk*a=6ox)zU;K&uej^Z;c4L#ZIGhajmCa1Ak`qkg*Hy3o`J@KckdVRZVBB>*t(4P zRRoqe6hp@l(a&lJcLKGX-<>Q0j;_ z78pCfyjl?Fn&|4;d?S=Km|6p0VM6dJ@v`TIJbb>%^r&~hUN%eeeO!352vEzLGnH^# z&eRc2Eqex4>Osk-U7wLVr-AcP%pWzg;;wYUq8$XDKVlPNH5HngMukl9Qm+@qY|n{m z-JTYIO;9~ z^XR|^H55HN`bvwar?rjw^U+QKrP#-?qsb#I+rSdc|7EwN!cZUfOiF z5M>v+>N(3Ix`V`NkXR4n%Vm_#IGo5!I#Dh)k-qxLM;1kf9`0vN+!!BBmRlPee?p|X zgQzBpHHfvQi*U(Cf2y`pTJJaV7PEelDGj)NF~XfB;iP{apwgN|lYW%eA>eIJV5P@< zVx3p)u?!|-GB1UCr|Xe|5}aVm+j->`Z8NkG1K$`{S^y|-r8)9zL7`yb9Vd10ES!K| z1r`~-Xg4Z-YJJzG{kMGTTwQkl`~tcam>Ai{vaUsWEvQPz~0t1jv zW0g1LH)!!U(O;0M@DU`Ujum8deH4EN^rvwmQ^Vj(Oe(1d6C+7DQ3-tH;LGJz?}bTd zX*f36AV)s>&JMOl1&rzkvr!Y!@%!kf?m3A?`@N#ps3E-01G6+#*DZ{82()vrOtz4@ zd^Ul#6X*fLRMJ$W43%U?62saH`%V}Fxp2lDZ`RECa%CuG`iN}qwFk@5q+Q@mj}X9%nBixCL_>Fgf1Z7eM2e%rrrWl2mLUO zcD;j!tkQB9SG{EwvOq+tczM&GIMwKYum(^`pV7qEpCSw1Lz; z;rWh}K`$6awp*O+`9KZ0aJqRo#AI?-q)tn!-$qb05|#OjabJ^xiOBv7L(WQ7KrI?) zNvuvKVs-v)iPb41);()0z*-NjO&l2qqdB5FAlydp`DTB~+&4)g#lVu~y`^0%X;Er; z{VI1W>APds#D?sJt$NAUoelmAwHq5b4;y^(CjMoN z{H@scTI$;N9v>Olt4xst+c4c#@gP8NPuHgj5EG=b2!(}U#N=7d#onTUt#mwO+A`It zkZ)x50YCbHwpM0W295KP4pPSKv9ZUcjlf9O zBNX~|)z|PUg81mWKWLom`E7lR8~JEubPpEuUMS;=ZYcH%lp~Y#oz8K8kuOi~cn_G^ zSkZC^-A>Ni`H5?9=5s|3;|VCfNh&S;&W2IjX^X>JGCL_al1bHziDP7y2Aq7{BTtN= z=RX}j|Cx=XhLqwlt7Gk}o-9zm@JBf*i06|(R23>3xiO2qVN2xx6#?^gW-J}AkXRVU z6xT`b5&7I4p2D06FvN9xPmbA|Ib5jy4W3yTbjE**;K@4!W1Uc{WP=&(sGnmpyAie` zn90TiF^3;)hz}fh58m^Z?7@cB)5MHspu1+qd;JCLeMvNa#^oV8*UR5N!iJsVxiVjz z4y)br#V{Ra$jRL8rZ%J03J}@yM}{m230Z;M96J$7j!|~XGBnzwpt3b8dZU{j{8|k* z$)$ADHER`9-=O_{0b!0KInE>KRVUaLge98;ZpmPJW8Q83l6JMNU|YQvFDS$|*Vs|t z_*v(3p~fCQ)bwH`RFokd;0Vz+a`%`))V(nutviQMcgqqI()PeuSwS6fwx#hHZICc3 zd%*xL7Di-9Om3!X>U1YmT{NJ(Bce3w^fttd*?1~-a%VA^6E)Hj@aBXBh=qYZj6sHC zrPGJ36e`q~?ozHp_hpYLhR43W=~J5H4OdHtHYIDKR1a^a-sJwOt+Na5+bDu!QNY36 zg+w2#_;zxNC`w;;S*FtM>7KYLYN*A2$B(MIa@}z$P_2tDv)d~5ybz!Mz?cHX5{+9? z)gMB$OzkF|gxivyl#A=m2Csa5{TctR^f&s+ z)ijGYF2)-taew`Md2O`Y?VYWy0RMfovrYfDyZlVQx{n?Ooz3k>?JfM@PSEb`Y<4&Q zD`+ndh2p9{;bF}`Au>k-ncz?84?!YdofYG{hR5|?*_MFV0?mz}G{Ow~kOc7*D>gAF z6KM9Ct~-|^y5j?R{&XHs@k}nnBy7RwA!vgqQ7}uR)0v2~2&IERzdZiw?T6#w>6^a> ze}4M@{nIzcf88T{eGFfti-=(j#~fH3x|oEM>FxXAY4Gmp`{S3-KfHSSK6v-x{kykEhwB){kq!$9!hE`)(hy?8k_f{o zrGgfJg+WgN%h7<9WYByg(0g$|jmEXg< z8=pUaUO$`6*5l-CW5n>%jRS$eah@ z4>s=oVVZ+Py#dw5j{uHL?ufr*Ry=ShFpagIPDqMX*nb^B`kAJ1JQKsF)4sdzyflTiWBB1n;4Yyd5 z?e6HHA?%Qt0_G%AAzkDVlL3{~XF^tJEfThdtgTQwh!7u!lOL`Ljr4|#2xAf(_<9lU zjiJKOLAx$)0*Jra0(ASMFinFu(PvWCph|ca;aH*yMk1%b3k;S2E`kSLBfD|n=0 zKcj@)KhZ11Yz8RoY>`t)+GABvyh8QUegprFl1WH6tkWLiY<&iG%=z3@s^2cR(BO7J zXCvj7nrOCczzw?@_Hs2o+s)YBa(ncpEo=l%zkKhlW_<;$hN*xy)`0eD-F!CGU40~( z&88#1qnihd*kAuUw%3e7Itutc#`&?+99`_tZSk-`iaM8wi z8Ui!#d1^fLR#DD5*jF@>a_jUc6?8u5mY=kdG_Z-Hi&(E^S&L%2to3@&CdmVIxN&Kq zJ5-spSmKN5q1nNf=$g^9mfI&^mwbCpr+dEMUFX>36sHw3?Pj-#DepI!4}*U)vj21t z{HMc;0f?+k+e~#44+nIfiSb(+?wId0+To zprFCe9{LQ~Am}I&6xtiWqE2UQk+_I@MVK?Jf(nbZu0i_Qhv>SlUo&$UG0f9E3b%SWz*h32@E&m<`LT8F09hd&2B(mq56v>`Xtc&zi z?NXXzfxNyVHG;NO2JnXox6zhLjSy?(%SQCp>;eyVMpaLsBciG(BXMR*;vI)0n0opO8(X zK75n1VR!dcbPC{b4r zLC{e7YN1m1I2d&Fz6+kZWe~)6mC{t5aR%SiK)_n(?JCF=cvvAetip$qXhX_^+Y5T0 zh7)U-OS+=~f2}sS&%(2}r_V{+S{vJFG8+e9XjnOG8J@zb6~%Z>Ixm$bFRU-YpJB9K zP6p8>9s#%L@%j7bo89N|+~w!vc#3Nhyx3}q^4U+sK=A6ZsDq9e&v;Sj?6fc_F8tc; z7!7`*NV%kheLlx>urs8uY#tF!=rwRpZ^_jR5TJI|C~kHEE?N(U18lH;x%2q+bZ7f? zvnAj5`bmGY+oz9VzrPti>OSU=XK2hC@|TnCDEhwts2j-5shY3j@NC#O902GT4yUhv zM}2bMg(oShDb8Dq)%0s-dH0JB#B4mnSoY9|;L>@Ac%@&+7If`=Vgk4?ali}@8;`C+ zAjNdVnF5WfCqp2J2gF-u7Sw&fkt3aj$VjRRhje7Cm1TnF>6l1Sti;ORAbfZ>Mg&qgtF}DigBotQiC-|?(0cq@ol>TD~ zd}}og27RQ%p4jpNKs-&k!d1EzY|*lbGT)h!l;0CS!P?>b^f~jrJ@1>6dlG%tkXaF< zlM@!CdBHnOwa13_Rd$c0qCl$Awk4q|V|Ttc=wl_Ofth##-ZxwIfr-=sY(X_rjaf8Z zr2@UtFwIP>bQuyrr-rVi5yQ&UmZ7xE2PQi-SwKFLzT$pphQPK_$%2*`GXsG!mTHZu*P0dx zDb(amkhEd2tbi`g*z}$Z*cWFmmCr$Fa?cH=OB1mlb>?imNDK>7uK9+ zaQve8=cn)A^gg`#aCG>h_x|wc!>ePgqPGJs!?ImTY^u_1IL0lAp&d~k3Fi>agtw~s zB43PwX9=q9`qVCqd;Bh6q4fCA0zel%3L50znC0CST)M=Wb+1Frf zJGOYu4!!;}FNKr=#Dm7n+Dzp(PM)o%QQ6u%73^1xX4GcvG+xhdlN`j{EmA%3-rbOD zA&JP}UaoK2AV{9+4Yfal8N$3yF4szGdvHQ>ne&k|kHYB>c=02^ES;Rh;59$XI}_ zB)%ffk|q{2s-tf#swyqLHh7l?bD|rjL({WH%UK^l!-^^mRf<^Os8e_R9l)2aS57Eh?;n@kTuAaNt}#07wXjtI?$Z~)9QEJpn5+e0h(ZRpB3Xy zc0BE4sMeO&fmX6B5CnX?Ji;>HTc-X%c^)ST99$r=Yrx z#0QtYlvqpCI6Y&+BHeqFSO*~CXWVoP!cXE!#38@w!;`=o5PSdP8AQ`~iyKwZK$9ZO z`67#`4gwP?cq_aSpbMk4k=I=demeY1Z!kO?X6diU9xLrmcXMld=h5TupFVs3;_y!^ zd*Yg@G(BZWPlSIpU$Z)FzTxPi+(rIPk@k{{s39IXt!nU)D$Az_0sC#D^lT7@eKdTd z`Yw9Pwb6Ojz`fB&pUdUUuxp!tWdwnkparVqD;}ug0XOt( z`{TMPE3D!{4thC67McbH$cTcTJJ^(oPr#o%O)KsUzSA$Soo2uLs6JlL8C2F-a@_Kk z6`2JYMjX004E@6oKj@_{CsjGj85&cUCtJ(p>c1Cb`uNhIn2$RPTDZRtOL%z;+ODjv z-}qODe<|hX!-w`uJ#$t}j=na2Gv60=t&GwAGw{2{cQr`I1v+Md9_|j!QiU_h;d*oK z&SQCQWJ!GgUDLO4Et%~p>Wabf$hjWAvc%L<$ZvHj7sut4!qc25@$BrpL=*+Ro?su_bYOs$##U4T9?v*T2Ny=s9)qQAzhN(>i+&O2-vwhti! zdK3e00+Kjo?wyM?c7;8BD@O%z;e7}dPk7?gDej<3@eF#y$RN%3hiK{+%( zBP;~1M>ZLK_=tXtbVje=3@2tnIc}N*Zef5OZ@WT}I{|bu&VhI*ez zn=##JVvPq-wD~JE_0f^S0%g2aJQ-M+YnClVA3oW6g^T+$H;*vY5#B$Fp;WULrs!9| z*p}kiGKWV+ALd)$=uJ@24~ek~;k+)rJOIdjqo#qpaS@x;I+&X|;f=I;7<6Q81ZdJt zs=}SO;_He0HzuJ3968DYe{*6Ro~8?T!q$-yTY;uRA9Ud)Vkbhz$ojNEXH2Fr8mtOR zNzkT24qG${snjqg?7Ot0mZ1S>g?rk z;MQ-mdA%Wny_i#f2^3MU(K?_&tdoaI3^AF`|SUZ_XdEo3YQ`SQU*GNtYXr73mGRu__;` zI^$xE!>tnk)!QE%FAkr5_>qnL&`~^?BD1MRiYyMuHnKjY0TOLcvm)ce5{L3;;};lE zr}4Bm4kuR)69IQJLK&g-An`eVsyg*;=#;JZp(LzePTW`TP~rKqQ0;IC!U_2fuW033 zoa(=vWZmr@6B9ZUD?!Ar$QeQyFL|IQ(Zzfj)e^bpu@y(^IrTHaTjz7o?_sVPb=}iQ zWTLvK2nz4l4gg2KLRyX_LXIzr5F$m;z=M*=+4(5WCJh(ECR&u+1VB5I8c^`rhNAjF z2Y&p$yuR2G>hG{qYZ-p4utD=uO2Sry3GxANVT0(#hbOw?y!}NH&CvPOKsFtRqY=52 z6T;%Yp}1u+wA0a(2Z+-{DvSl4ywgS#9PYS;yKNdUQ*))8bG1KXwj_oZ-*I?#5>>>S z1A`ORYQsLBy3!&SCEDn*VGtTme}}Hi6K!iAi4-w)2Tj#m67qonIJXnRaob@!cHges z2~lfVT_A9U9mqL{h*>Gm;cKE!)pWLl8{*I4a=1U3gS!9ekxHQ6h*;^nNxf$8B`%Kh4;FPFf}`lQD?%OHAuS&FM^L1k>E)wv$NqSg{H zCP<6mT*KnKyuJx7KpT3M{nz>M#5DldpaxnY*@F^+)uatCofStFT5;D-c(vHt2^GHq z)-bwXz#!ioQ3`qL>#~kv!DrG5>wUe+qFuRey7fUwg$U=2IL5{ipBt3=$5#+H4fd|- zLVD@aRtTPu^2i}Q3R_C?sk+;bYVC>$2Yc9y@#+12HjF%239~wVt%V^KGpbd=+Vb$B zCi441(Ju>8vctqof8xjOq;Sl{rnh0;hc$rYnT|pP z6-{%pJIFv^M(Db0#Z614Kd2|RI4NyY^smpfz+Ep!mm7*Y{z~r>dIpUSy7xSWF{E3oNA=B z-eMq%L0i)7lQ?%31xemJjY_bhf_nz*n(isyc}w9WTSkC(e}h07j@1W8BM?pI#>soZ zLMD2!0;o%OKH+Aab5Okm5uqII5GSs1xo%z;(Qb;@8stZYNT&;lU7IkACWDcjAYOUT zh7ZT2(l6lJLT=Ske=fYd^p{ZoBd?!(?|%=Xli683O_y{9y!`%m`_b0UmV5vEQMY?{ z|NA!n?(Toz-T%J3|6TR|_Y=&5NLOx0PUa^iGTocsqxdZME}r(Y@C5Wr_X8gl*SuRE z;ZBw-9qR!-@;FSbn@HqS9fb>4bS#S|Vb@otU0pl9@oL_!ALhTx1()NW44SP4YPl z9t4l2=5oIe!y4k1UI9bg=4E(uj3O63zVt23I>H44t8=CUoIoK{@aXuxNeONGf%e0} zML6ke6tww?G#cmv6ym(n>Fk8H9F61NoUy}}`HCb~TssKaq{4?z>gsB4IIX+Upl#;H z=o=Uod1ZWMsl;THg`?yr5vloE0)lWTkIW12P74iL(_g{mOSMGv+{Ieaoj5hFR#Q|f z5gu(6O$_>bb0Ewe1sxhpq~g%@EgTSmmmCrX_5(xM73^Y8<*C>R8MC-t#C&-D?&$bu zB9icXVoxKqE%QZd2FSZXst$!k*ts)M@uEabJy^RMZ%OJOb~N%z0RIyqKTKdV!&SY)9LUs8t@4ZtiDmZ z-NIEkI)#5RZ^GjiFD`5t=ym#-unJ3_wuBT4Rw%Kbz1B8$Xy$@;qsxpM1UQ{;3o|+R z)`C1_e(M!n9*Y{N4sV|A26!=X5>M7(HxZo#e^IIc6uEI_vxurK2IXrcYykt zk#Q-Y_5*4tAP7TTYSTHSO;N?xWJPkWNQu;PW!ij-xg*u#k?MZ!k)n2~$*vkJtEDt) zP`^y@LTuFT)#krH|NX~Wee_?s{bxBzz~|V1Iy>;vvHxuDY~9&^ZsYIH{&Q#lxwHS& z$^V_Rv2buaL*LuGcaJlw243^aUJa%3t4F={%72baxU@Fr$p5X*cH5EvJKOC$`F|^a zck=&E{@=;}I`Us12B4T6_75tU@Uy|jECcFnkQvSi`AVw@8wP}nk4nmj&K1F~$XX+V zwsKH0+7_DzSOnOU#xKsR!xk?c3^Tf%CfeeIfeGmtg5v07cEv~S?&kMKB~IByy(B-6 z2M4;+uXgp11=T3=1pZEYV#8iq5VrQ@T9Ue@rr}U$_|ayo1GRsnFpJv945`tyGyY%? zghdp8u5wE$`HVcBc@S z3pYQ*m}zv`pZP*DxUUMva44y!!W8@vjKfb+PqeaY1GW3n)Aw$CaCJT$Dy$A`)M)vu z>6xjLR&eO7EG~*%<|KJByKZ*INa^YT5-j=TiN_tt;B)rk+N)FB6N2R~QNzE}pI86C z7~@QjmbC?#qyKlewz|3e51XAk{r@)p?)3jV{r^t?Ur7I70o8LHPc~rD>rXPD*AAsR zLuKEy6F`r8&{?YQ1;nxKOQ@EdVp)4%z~G*^r4CU0FtT0_lWYc5{+C1PJ7T*P^{yD zm59{!Dm;ls@4^JBk0y#}G6R@F|NK*r68h{1?G`QDWY0%rON$%s!nw48cnV4Ap{ z+bn`;rogQUj%+^avarwWqx-JRJ`$ET-8dh5!tDs5PXKd3jK2yCq2bFdA@kdF#vf?9 z;c980qATu}4t1<5f(9pQR;?yHP+>O6CgFRX$}&YZ(>#kCf~T=s7B_Vp(<@O%wBr^v zhRhY6CALC)nkuWwp(m_P8)H`1}^3Kc30iOE$L(r#Dt$UxNkXps4RW( z37mUDg+F9`Y}SbTZp~w32y|W3$p_y)yf%tuS#W4fqu#%&u!stRYURU8R$GP zO~u4Z0M%{Gg>GYp_hXHV@{$~WWD2{nWTedNyBz+#I*#*a1{HMA;TJby{p8zT7G89^Ds4SU+U{$;dUMOP_hB2n1Jyh_0)qg?vV|6_! zOwM}Ns)V54#FImmH)Ilwp1pp3zI8U!Ss?$Qt!&kKtgJ^8u^Xr#+c16c&Ta$8FTDO%oo0 z;l3P2+3R?KmOyOi3qGSZj%-DD3b>7@1A@#txS6Gx z8EgcP8J_^d6~XGxr;&1x@`PB#hYvM4UYvYPLEkcFH>g zM08{grVfFl3Cs++K0Cd~n@L!v;jF-()mIc-UA1Swgdiib`t}i~fVj45o4_Rmks`#C zM^%-w*R60m#iSJ^&S7Von|Y*FGTzn8iq#u<#FZ?~i zm@~c}$-S*LJ$!+-jG?r`11dh3U0B@@{$;I_;%1I#LH`q8K+?xzo|RrLqW;y3qGDO9 zUT#l8vaN}JQQ^s_Ez0!^U>av3!lJU2_N;S(F0iWRo6^kBYI!TD*7$ho#0Ib+Tg2U*a{3| zG~?AOYLH&Dt!tQOX|c6j8m5fpKI<73b-YM;sY}hAVhZ7Wd53dHar|jEt%i`dYL6YB z7lMGg(s(!#TTj!tPpYP%sR2Z$UZZdwn3h5ixutZYD8W1%Nov!-K;d6b+m)=2weS;^ zoq*OGrP(6*O`wYoal+9k21V}g%fwq9Az24PIbPt`BK(LtGg2o#$Od@;&dkz*O6Y|> zOZu}+9ulRq6EeY7!$HtSM04TyxslOEJIOe9TdYSfsX^Oz-$R8;tp2uowQ4=jn*d~- zA~m*QX|vpt(Xe5kYd9;+Dp~!ya&56S$W`lE952Om>7l(4c&}!>>U({I#<&SI$Gr z(LeFCcwjtu=)&3A*v3Yk;ZlJm45ID#`{ch~T**xePL60TK7>+BeY1>?Pv zGbSIicfu&PV?*WY1ICQM1E>GP_g`-r@=~@+#&UGS+$mg+J8E219 zLvz)udF{CHbG|ivGPh7W23Uq8eHvO^-&6q|T#%@}B>Y^2k3BB=yHRvku*hm~AdcDW zd9FtZKbCZPQfx9d!Sa0cf-TV4CVI)L)`ZXmYqnvjecmSXBs}11g{ls2my$_1noGq3 z^{0~3S+0%xbtmU&oRD?YsQM$6#aTG&Nd>zM_nWQfb4G;j%TkYo4p-h2)dhi+sqn2D zlhwm}q8UqdvcFkkPN+u9B&4Ecb^Vf`(9Ni0KXyq4^Kph&_in9s74^p(bjndNzkPQ1 z8TN4{hvm>?*=Lh~1=IdqE4enjkHhIQjP3;naT~hsNeu%v+xF&J0B>xZ=4R@f9+zU6 z=Ef^qftPQT&e^(aS*34akao#l(IWj-jL~^3@?zHLuV#q$BRFT6^wsDzTau%S02Y1frokg1QVx1y3GVPhv> zr76u?YMWQLv9mJQb*G`cZ_}!NH@{84k>YFeM~;KPDz6mw@8--?Y16Pce#>KmxrkOD zGTYLlhVAQ~kNA#8ZrXH}!7Im(+)O~163T|ws#eu+U%8x$x9YwsHJEx=j`_w!EOkRm zqHo2iYQ?-s`)a{58(T#9INogl(T|a-Ua*O;#TJUHnC3`RTXN-4Eg_(TF8P|*MOey0 z8|lSXvOMk*dJ+Bt=rT|?55_EUy#UGQp}jEKi`U%cvbX_w$(&xehA)xp9muyg3SV(H zcp6#8q^R4KWzCWr-I+5?`AdRJINeYo?(AcMltZy`ytV?jS*>!gQiU9tI}6bHJZ{@G zs!dey$lhGVP?dKO`w;zf2IO+<|y^^KqD6BT3RFjNT2(ExAez)FI#BM#ak(^4>wFynn614ChG7!|z} zM>k9bm zuHtrdF~*Cy{w{7tw--k|SQZH0aM8A(RRcGIT?`hwT?h2dHG>OKykAL4@xjVMEj*K{AIU1O1(5mO{JUe%F{#6URW~@2(?@EUh z1%KR2N10gFFD7#T?r|mlDui-w(W(u86@&RLJN@3CeZI1Nd;uHi*E2a68rQ0ewCdOj zV0T9RZ^VdSs({>? zjZ}cIwWA7cc&x((u>w514vNBIH^rMqpDTCXBi%7RSM@|Um!@Ugvu)P6@zsS&aBp^Z z!D^z!y_>yYBfm?z-y6Pg?Wm~vluALx6$STB{3i?r7f?_>=;MaU6O%UFw%%8Mn&9}* z-b4eet_GSX6ZJxvd*grO{G>3E7>oAiF{bC_|Jd$qI{E*)@N)Yu{`YPC-NpaDi~oHW z|9i3c-_;^~7vzh@6$DliBmQ>ogj<_jFja?rtYlTs8U8W0=q^Aok8CkcXNy5K`l%61 zQlFqwWAP{d#ZG|)my}7ts7i(MdON_qr@esHhgIMp_-7c7P?0|-Jwk2*2owe+;v zkiHSxgf4_zvQG~?}OiQE-Ysvln=7Mb$DL|f%&65 ze^l#}U{S7LG9eaW_DbYHE_ac6*9sI??{p5vgM-F9Obp(#@Q|)mQ;Pujnd0=;hMn)} zoEHAiWlj3e`Sb4oM)BDa(?8AI|7~t|Hr@PBo87zp->v-J?f>rfe|P)8I{QCgGDi@Y zXCeXAy+3fC^Wc})y;pC4?7e*b?iFY$7+pR6)Lh&S2!HzF^azu4=|K8qlNQwZ(h=z+T~&*6Y#!Xpp}LwMI4T-E zNbTGYpojf{FV_x4jYf0bst4Pc2fMquzIqiufej|I%CSgE^ZC|AC1_hWE#6gbn7FD| zt5^e??A)oGOZ@ZdfABJ%rtAG>82|rkp8mJf2HET8|K94h@ASXh_`B2p?)1Mq{coQB z=S{|Gnf!&wbWZ|kC+)n8r+vx}R4M%@9VhVp2IAXXrRcIhi9MADl*8G4c{u29Z+E`; zo=NCuc;M(!(aG#g7`-se_5)avlV))IqW9s=hoi$6d!@y`$W!)ylqA8EC-`u({5{PpwZHIzkY}RG!UC+V`nRPh&A!U$M4Ae7eu2p zs#-JH;D+G+W$^#-w+SlWBS$aM8uE*0KlYA}VZxE-I5;`uTz|%A(bb0!;bU`kRew5s zCTc1e<~MwM@7|D-XhwYwUJ<5v(<(}a{f0>Nj^olYLVsfd4=gqsj)$2hto1s0!de)` za-O8KaWs&pMS)1`{>%7H{9~Bvlrv>y+mV-%KXnHE&wYkgW`u{RIqJ3EijIf^XnP7R08UZdpgCb8>|oTK^7&&?kXk3sc&`kLtvHCz#@M;;rYaYn*SVQJ5!1{`oYJmVynIqBd5 z_dPN7n?Jq$@x{yM$16=KA}m1(bn2z!a5Tajo15J^)Db9n2*k&@(|NKAu_0nKpe#ty zmACJhL@OXeSNIpN5uLF?Ht zdkU)m)sxNc0s0_HS5lp%fOu1KIv}@p5M55=B;%E%$g7-A#N}LI_TDF?*6oWE%Ih1U zD`J~GZ{qGoJ!u+R83LfUIsX(3S}`1}7$=pI*F7D@&n~5}xm=fW+Sw>R!MwkenxbGX zPNe>u=V>wbqst7hbFv69g&45HJW0S96f_+sXDPRizfcftcFG08kFVZ7V>y5|e1gF4 zGB!u86w(GnRb?$fAn?o6_gYgRS8Xx`oQ~qpjSkVn>S2LqCFO+@?pw`;`;%52YbAFp z3IV|g8iXQD0#4-!|2$eD-y?|EB{nH?+Y#HCDOXm9{AKw=r&1GQ~alxx;$U`sUc?A6=nKfgMj+sKwtwpK&i zqM=vEFJB+dZDw1QoZE;yK09K39^c0Jh(=ak|MlsM7w_kG>#;6ci+JCw%@=Bh@87#cPu>WHN5HZ-I=m5mOIuc{TbvK)V)DR+_z3Gu3q_9;;t<8r!rQQ|fxf_E@v6 z-rSZXn4z$=e40h5N4IPbJ~v#WBeJ2Dqg+SQn{;GHbmZ~; zjvToiNsW%=Y)*91@H_<7*;@H^;*yfJ^rxpsKk=@P?w73w9oX7^ck~_X>ArjZ9UFx| zd{=E-M{E_+F3Umss@s>s_RBjj4D+{QOHg5$R@-tOW# z6#!b-Xwq0m;lS$3$vOpWqP=8UpK_MdBuc;F1SMUS5rtRMaeN(^nRc#MS(G*q58cb&66Zi*S5>1^w!YG=cqqWig z!9lQTtDuyJ6-R-xu<}6sy4n4x2N0n=fi41s__TpVnec)S0XT->qCn9+uvnypjdQud z@GMHR-CcwX)JvYo7fkE}VuV(pYvm2{b=eAM_EOj=;)6F4ngdA|Lb1qWs5(vJagPSR z++Ow5&qptRe8Zwm*U`f5!*>;pRoo?agR!X@6K}L)N4&-?Dxvz*D`($D`U*^sjS-V-VV9*3A98n9) z&8{ZfeOXUi4n2*k=~7Ns(^7#|dC3^hDEexKE)qafHTW=h*G}j)5!ocFv^m~4nJ`Bf z^|2M~Y?a&gjR6yVIrq2WUanvXjsfv&W$sU7t5(OI4$e z#7Kmt1TghzCRbVkXLpx{0$`aVcQ;;KK{VxLR>*lqZ`XKj! zO+?-GizpeMUK#RD*R{Fin(xf>Cu?x7T{%n22ukT;+M~-@|NN&mk)4BLd)5m_pTn!P zm(KeAhz_Xd95Ip!gIwKi0VR*jDlTPRDNWsAhv=uV}C7qc|MU)?3W5{O$x8olaM* z^zb?tygnzD1%v(lU<4mt!bT1+{|86to=y(}3 z<>>f#nJIq#yjyUd}y(XJ+-X zng(O5Mh(DDOqhsaGV$O+i13{@y@SHUV!^9nl$Ji_`dzJ^r%W_ycUEHrq`L z6n#Q&?i4it#Vm5|q9L*8w)dR6Nkm+Vam05UB(emK`@vJj&>e~>O+%O`;b4&XMk4(@ zgl@w$l@x7iQqZ7u6|46#)kJ%j$pPSclXw#Sv5oQ4U#DkJ;SIEPc$w{qE;)(81%S>j z5I}*zv*Bd&$F>{|Q+haX>>+|>^?R`hBQW>@qw$B}dt)r}G$s3uCMGu?j)*vbyPzlm z_4esnccV+)DEO1TgPHcnPTTH=XM*5Zm`t|Yc#YrXh?aKgF-TL?llKU~=Qv>x_TF%? z3uJm6$gW|}P~ovU21-z_W1H6afVlZ%r^4VA_A02|v*JM}jH-?FW*6w9hucFMC}9t~ zgx)M8(I7evXQOP_?mbC(7EL)_-kN}U%bX!|3w7z&M?ca@WAUPYbJe(oAA59%Vjq9X zI;(8_GBjeXCg%lAKb1N$fl})*bfkyZIN0hhfFH3E4cp2--PlBNfRyw!8-W9Kik!Xj5Z7Dvgt>sjvU+216QbThjqhl6z zC>*Hyags#grvhcmt5s=c3@#LTVF6aleZ}GMiAH4n3wuB+sWRr+h{1(@qr%8gi*ou} zg%Jk&J0o08$E!T7-HO9{(JU+HgRHuHTZ~hp%oZ^YO`vaudrD+OsXpxCKs*<6SRp4U%Q#g?kzj^1 z5_#UPrJPW!t?QGQxzB53DT+I3g2a;;NC9)F&=iYLgWr&Lzw!O`>^x2>Gv9BVaqhQ! zj>H)UL2XnLPtO0NSq#e_Y9Ohc_*FJKf3zbXLTFPJP(Y?*UkuPHZ_UNmoD^wBj310FP;3o^g9Ka%ex9r75ryk+k*+|YNilk{uz z+vpoC=Z-@m@tC<2=H6{`?;LIr!p&2@lPgawVDqv`15^4CskV1CMLa~BM<$n0TD6!* zEQ>n&#xOKD8H9=U-U;)Io4W8xJBZ|SPpi20i8-p1_)WV!O4l)_gZ7ca00N*a3Rso| z4E&3U6tP7x)MZjf7CW#ditfRl^u$CU0;1)IX8`+zuy5s; zDnp5&?&PkK-!glNxhQ%exrkiEd=pawUYw`~LGO9`T6`ndRiZqeTC*gHCjBdE6}b(c ztx)-FNiUn6!;tI#qwZ?a7}j@E3Y8ldx#YZjbKKdf(JF72>Nl!oZH|6RGUnm5kEEjc$Wn?bI%yu!O^-!?t%dAe8Bpuc~{YG2Z{ zoSb4)0-FwhXMI~Dqq~K@u7<_77Yh#w=Av;ETI|?Zz)Y%3i_(cy4T(oyBx;d@u`qpS zQ%ud?=YT=cGW<_YX=C~nI39`A$kR#}KnR%Ri453G~1VURH{(L0aA zflAT9SJs9TOr?i=6K-i2O}3pKj6xZV(=*sdM3YRu1WoB^946WGctVLEUrtVAboghx z4l2E3$#%i2`8e5qFr^TAMZR48u{Lv>ZRMGyl1;0>2NZ_U~rlixb+r5 z^S9QN#f7)%J}h#f3?_qK5`LD$TqBsln-}k&{u!i6#mjJI{*H*wsbxLLg*V`6PMQud zvb~aPmqm7^{)uod#5|d#vYG^iPO@Ddm;veh_M(#}WSu*Wyu}Ho7 zMex%nPTew#4Chz94HF1`!kbu~ZFDOwAbsPLc9sP-wP_WzJXA$8WLaS~SbN-3Iks){ zAJFpx1C@PV;O6uD!=uCZzZ}Bc%iVuo`AaRc-Hm4CW|1p@F4tKiXP>$|t-X)REQZz& zKIaT=1zHqVGC&5yDq>7f9l55$?W=Gc&n9%?ZxT*oVm7{hbrJ=Wc(OK$&OjJnMDG2x zZ$ijy?nFB$kK5npgp6b}xzGNCEV(>kV=`Z*3+Foafb+MD`JVJt$JuS&bFgqlu%=z* zhVo1hY7j_D1%e^ImSnR638AJ|Cxp=Rw=WJ?wAG!n>-r)DEp0Je9#3DveC_uf-jC zOPN%`Z^1xz($-N#l!Djt>x$L4peM>4WvpJF9fw*M>))0QRgel|nEdOsSmyZqnv#aRD$pE=fB(qu<2aF?~?8~pR;|43yZ z`sK7yp8sQWv%S-H^M7cLgd?`7 zmUq7b0?NdE6p|@E`5Tn!W#j>;4gK~vaGfpO(e z%SAZk| z8oOipMYcf};4)~!Q~*Fv3P7G%0L74$!c^A40*I*v(TM-$z{`6=dEvykA@{OJeDHtuka2U*TcX;@g$mLsaw6M;{2M39LleQ0Hp8v>@NxiyfF4k+(j1m!>di!Nv}}n_KJq+1 z2;haEt>p*F)?CxqC!PF#zkom{w{o|Hd2GrrP-<}rJF$InJ2^61O}I4lx0Wa4dB41kzmmftr5aR-;`3`N?R@@mSL*{p{QU0yAuh1;q{`O-eaULYEj zROJG)D%qpb&*8LD$OP;3*%}%aUHCeiws>Hg7BXt&eJmE^7OVtA`i^70y2>0PUkOIc zwQ|2+EB71o+fm)&Wg7ldG#p&eTIluE#)_y|2FEP{DLgx1RRCx6;0itt`@Jxg&{w^q z9iCBcTs-#g;f=H>T>qdUM1fRyj}P=EgvF3pt%-nnu?B?CvT#9&0-@g(pGpHGp!0IB zQ0fWI0RFjN3L0fYQ;vd7lpAAHX>e|ik*OE^a6^oQD~z#?plhBDfhkQ7MiGy-P?&k# zw5|I)x!Y;tt6Bu*39qeg${QM9W(iZd5#`b?-oqReg~C?A+#wf~p9f9r{+Ps(&iab* z!eTA4kD3Fa2$?w`)RqAtsaRxX=!gm}y`!rPwG72dVC987b;G0#Q7YV$JIzYa$`C9E zXQ}g?n^Uvf-kegax`ey&AnfQj&rRPVhX^|LT55CSBI;{^Hbk}IQ!N9$xg%3pI}kTE z*gDs^@AS)<_?D_C^(g`Ohv0!r5OkXA@OA!ycyS;6sTpAB2;(dEgYYRct_=%03tqK=@<$B&Nm0Ci@ zmZ)G(Yc1%>aZ6coOc7lXxI4uim8JkX>EW0(gEbgo76vUg73l8CLZD|(*xRB;QI79a zQr=|jEOzGB-o0z`%_V=+q8&r0A;P=&4EUD9e$+?Eg1eWfzmBTVz;w@a$c-biV_=Ucm#>wX}89X738q^vzd(Ft_ zHyUPQPyR|Bpbt*YxV?LZrs7Eo$kjCs{4msGK?b+d`qn6|2EsFu^AN;IKT@_W+eQoW zN(3Mmy2o4MU>@OuTe>ORp>y`lhHJ)z7ce=JWJnH6B8rlt)D!VwzXUpP4eyY`mjzY*{?jCMupks|$j#hT#EE7ObRJ zBSq0Kddn_zp0Chx9Q%KU87IUO-NNbppo#VmDi}2ABL%l=u)|pp0p*5K+Wa4OY**6| zy`iX2oW1ngl5KPmkTW>koQSko>=l7tl&&^ZlGiz?2B^auaGPK#SlTRu7KZ5cm9vH1w(nkch6n%72Y zHbx6HP+)HKbi%YfHs`m*{1z8k%gicr(X+46VnF5s+zGCPWW07m$eE3l05^879@A(* zZlLF%RD=E;mTWV6FHx4IPWOeMLQ>;w|XqJLX(}TEwza|RWS`YI7Nt~f3=YeH+ zyMGd$4JQo@Q%&Vs(p4RnKsGE8ak!A^g2L2p+-Ir&^&_Fc`CaLd_|3E3;4^x*jH7Hg zhM~YTSnz#+t&?MxU!Bh4y{5IG^HH|wF;aTk^=u|8K{w%snbD6tQ-_&5E&^Dy7*!Kw z5sDQ68!Sjs1eV+HEKVEV9@~@7qr}Ap`#4{9X{9eY6i}ijGZLO*SLI6TsUyOF=+0WZ z&b;ojyF1L7eQ;Ir_nW50TsVYG&w*Cht9~`03LGt>2$Qb)nT-Poxl?1#9kDbc;MX_9xDu|vJC%VHa}&5N7Cldy$wVKD&l?#>$o0mnLhS~g6fB)6mOoq(hi_cj;wSr-cQ!$NRBT} z>US*Qk=HH#2jA;hWBK>Oz^gxuL(IgYABPjQqsBgaZi>>aR;)!ojPm;Y$-b^;zvqyy z`LF75D3|}nIhpZXEzKXJP@z~7RoUa2Y?u12Fk9k#VQw$_vWRKi1B<&~+?MgZv_(~y zt?F2n&FXviY{M{(ps)=4zKP=y+c2Y9Rlh?P&E3$>m+4VJseDN@-XS{h$jDN3)c({S0F{_-nWqGVunbp#+y+qI54Q zs&Fxrcv?A9%$v9G#L>N*%YXt+2xH_poD8S45#fZMMB^dGIZDkCHF&_8Yg8H|l|?fb zT&gI5&7Yr2yoBY}8-9w9Rq0@;{ZSnFVOa27e-xgV{qwW79ZpMagte}U#qn+>zQMRf z+j}?Z%wL}W^ka~c@5E(ck9yO_WpSS_=k}>Ls@p5r?SJ##s@x~qDq!?A47~;e)(WoN z@gu|DB}Om5#3Prh(pXT#$we=wNGvT3=LlLq==juQfH@oE22Y3YsX!q5(Bg-yYGf~> z=aoy(OGVEs4?V4G#IQ+Wy6UWPUyG~)3CCYHW=wdC1UsZJD}qWy%sBNEOTdcLb*R{A z=J}+v*pwFj!Gw6XxrEu!X)Q7#I@Kn`V75#V`{F~ngzXqiDE7eklMm|Ko=~I;PxLlh zBBF19IecGbE%0O7DZ`XX-|k}Y?!(bfHKeA$QlLlMFTVqOFS|RSVUw*GYFAdWai!}n zQzg35YS%5)Z3?LaD71wCSK0FC)fIiZjX{~|>>DA>yAKP|Wv-H3ATqDYmx9awH$j$n zAO7;(OBVFrE1ys~@pn~W1u5GY*5@v4<=dEdxXLaz@2U{3fWv}^L8%snVrjEJc^;eO z$rJ4#OBGg|e(p0K{xM&2{i7A+><--$;ni{3%gcKIC>LzqMI_rT(zaV5@aog{W(z|B z_x_`ta~G44w@BV%$!XGet{4?7Z%&y0V?NDG*PYseb`G~sXA210TOAI+_^r$BH(c(E zn0=n8Mt1*}35?ucKw#kTx-9SEcTM}M`hynm?XMx=aYVjp36DckB;sq2$ub6{mO{74 zssJ+Rn_d(^29;>j?tpX`7!Y+!r}Ch5aOBRo= zXI^Y<0F~pc#$n*e=#zUMSUw^y@$pJu#~c^+@!ZIP-6fxpcjq3FZxv&@Suz^sy;!mlzB|_n?;5+S z8|AypJumCdJ20zq3|0QMpdU*f{h$X`HZjw{!6a~aOH);a`Smp857y?p+2h4V~FXg!7nIW&v64D)r+qNRK^ zTIxdn>ecOaxM=WwZa6seg`!YA{78*uYc{W5%~NfbN)vSboGRnvSQS zOC2sew*30Tbpr=o4*#)4{ycnl{FBvT`~EJ!6G2Bx@ams`S~hCWfBHF(-B+AF1&)=I z(N(r&q44(2tG^!KqFg{A69q&JW-A!Lt4XlNdkoq)+U{_5w0o(9svxuG0XQ9AMgt}k0O_`Z_GO1L*=kY7T_{C<@trhj zus8Zjvt`_@sMJ71L52S*H+ut2Whfm9#lfvN@?zH;)gnNL2+*BFfV9)HTIp0CB>{Qm z#RoM=gIV=K?utQ16P2uw=C4|P>{1^$i~GnH0NFuYWGW-LDf{+vc|CnwYN4)kw;G+3v>;FZQV`_3qA9dslzxA3Xj7yap+9_F+^NUHv zB^d!fDg*3D@%doYBD2jvSKhxpmWxahXVt5Jud2U4{KbHfL>JY8gbbu>Ds0^!sy>Hyx*C8r3&?C=9Skq}EQtQHVhf<&Wpy}P0-eKO6clA%tqx^dtFM1C_18Ku zc-&Xe&L%;i39mW;mU^U`C?wc?Rvm_raAcKH9l`xKI*pJ_&=Ll+jsGQ zZsYGR{?A?fpS$=!^Wy(ZlkjXD2JxgH>4-c}M1s0}EFKQFCv3%g;!(xi*t>U+lG=;c zuoO(gvncoiET3k*J|&-_jPYFHg%HMMb46>b&Y@&|YBU2YW75Si$!0*%e^n|)2?<0& z+g(S;3c=W&BC0bU_#3rzQAS8DY*eXAc6}_3QD{YA&MNh+UOfQWH3>(Y7s4qhQ#4SC zh663-tfBnQ0f}~e3f|OEW7MBEtJk9F&Q=9NMH$s|uvM4hi!WHGZ|W&ScN6*HHUOG~DmbCZPU z_^qH`G7|~EanwZ2PS3Cn@KsMzjtAc#L$vPt@7MoMHkPSlpx(E=U8w(&zGUlv+mCkI z{}pU66N#d~|Ks|fcl^TyRSXPgx0E*K=>MIa?vAVfZ?*5@f8NU9o&JBP|KI8Vb@cxN zZQpQ=*mK<{NS^xLCzi8{FaGD1|5gyvo5z4Im;XE4o84_&{&(9u-K{(Me;a>y^8Zf$ z-^u?v@t?JEyiVxm!LXm@UW!oC-dN6NHk94nzu}Jev+aJ!+2wT-!fe>@^}{rKA~v}O zfCmQ++@dzu4*tf8D)=~owyJhR=V99Gx2;5n8e9^OUW8frfReNHU?PREy+?ybAAei7 zF?9(_iy|J@4pQKT_5QEzkLxg8DkBi!LXMQ24OBGsJ~~TxcLBUkR^(&{MNd)80s189 z!&(c_#!mQI!mYu%(ydf>SPLCUu^RpcBpHx;^N@e~VGfF5?(YYWobvrgMmg)t7ZF0( z90}F$)akdGt(|kVH|NkGoMmxvVfn&xy>%R8mBvb;b72fguqu)WHmGR>LUS3UEJsac z@hU}aPz^P6L`s`AvS*c(1;dLwHp(z=P;?IEjAeF=iyb)nOLc{T?GN3A4~( z8{@oc54z0q{J;ARORREH6pq{j-`zSn_SO}QLoE_CXlKeG?b0th+g!Z2Hn4#SOmy67?oo3=8mumLtXGY(*4eBUqr<8( z>Umf|2G!Uj`*V&8*yQ15|G#I$41386i>g5$XD%yG{n9C~47dWHN@!uf3YDy8jv>|{v?kG|Pz$|i`?b&dDBloEJu3-cjquat43Ry&oJ(ee6%PJ3 z!^763fokbGO-6P12;cOl!TtSUt)uVZt{uSS>cf&Sl_lKkuYi!FVEYjB6VgUX_fn&G zbNnO`ds%F>V3YBEG>yVVxHX}QJl1{KW@pTsv^UI#u)h&(Dy}?XM?^8>KD|5I;VDc! z)eWq35)ZD{4&*MSs2-M5)$lDTZf(j7sC#(u1<&6wOW)wC6;N9(f%{s}x%Tp(fLuVW zN|R(RrAkSJ2&`Kfx{Id>ldl5(s9;s7L;?kLV}lGM zW}q`Y;Mc%JQ8+*&0IYK?R438rfRjT4%(XS@_uibr16WlCNsI{I&c@1~T%*hY`S*e) zbmmw>OY7t{MyF(CJnAHs_A{$94(1C6Dp**i^OREPEF4Z2nARcI3&IHu8mEf}Ld4Sm zek2?ME;p<1`&rBxNQI9%jviU%jHT0!O7m@A7nXy2nGo`f@SJ(&vM%+ZfODIs9Y}GG ziKLHlt~F6V0L0M(yfMRiOiTnBM3X_D9eny6=NOmNEru$!u4o_tR#_pcjiKsuJ^ph@ zRf+#RWcqsax#99~1L9Sk01K}*?wlY()RpF1co%im-%UeNa0!^>oq|3H{Qr!hgeq;4 zaD_Sl1g{1KtiVx;h!wEZkOXpW7K-l9XS6c-9#$)xj7*PGLg%XAo@7p6WgcRZ&J&;weE0*z>bV zjug}+T0`x#KTDDbsLFb#P*gwTS=?wq$5E`T2Gba5kH?TPC<*fi+>n4J+?dNO?xT%I zHdd34BBn(>j<3e*nxf>bSWM6xQc7`uj#563sYxjUZbkoaR}-X6kBH=1Qg}KqzSQ_> zJ70iQQ1-Q0DPDnO??s>ACW9*LPnn%W4RSm{@R%plG&8AfRd3-l65gmf1eGrHUXCJI`pn%z3b9&8m3Sl z&}(JA5ltzZuBf+3^#qwT6Ch#xQ#om{zKNVM&FOfTCc15VYX@P5hr>x`h~;A2Tf0b_ z*m&BVYXzN-W*%ciMfuunP?Ps&$Xb>e|uGh8u zH6!OUa@$91K8v@3+0cW8=;VOI2Wf01&8`jEp+K2-ad$)?5v7jttjXj7l01qL#Se0@ z?@t?R9pqu@AiwH!`-TFbP91g3eQp@!l4d)L=n;gQSmB9qt97O zafkY&-e16q7bj0tMW{I#lsvzi&8eVjhC9_ z;wAL80smKzvNI++>Sc5OK+z=FGHWAcwHaH`#W;7h)Yt_EjeddDuM>;e>O!2kbqxW{1@#Z15(7g56c2m3H+W>D`;6R~)e zUnm?epdfIX?5BxXUf;yOj6pSMG+VlfYe@+xwsru(DM@(_I(&6>!%-X#2tqH#c6v#4 z+OXH#6gZXN+xiuEt!b>sh8vlqTTN+!o~v*c#HZkAa_C3VHBnv0I=2C-4T7osM=LYEWxFX%S1(+cC9%Bc?LT!_5) zj?C)SbJNdY3QebRf}W*)aT#z$yOqIKjiU<$eNgalLmLLBn<72f`yedn-vMRjI2O7C z;%~Mi7*2sa6GS1|JL{$2Gf*pMm@pT+kVJ!7KT5ePxS6oGe))}0mNy=ljZ!2;!}SOC zRQ-9v;pmM69>N5GV4(mubipK^tdX`TVnBj!8eL97+M_@9B@7Gbp(jy-hg|?{HirE& z2z=_x5Nl^*gzSFMC^-FS1#2Drzttb43!b4xrsJg?wic4RFpqsUuK7nC zbuLKjn^AfRbOzMVgo8D48?qrw0OU(kNLYK`TONtI;~+9;0;eYK>evk|%CFneQ` z0)70U=>5bdw;-QSj!5e1t`K^>klA*(oDWe*x-$aT2muuHtOny^sk=nnKLt+^(w;rI z>Xfdcw0ACK6b;j*y4zh*a$UB9&G#tj1Mk-j>uZa8pc*CnFf#CgO=b5~j)QnZL5I|a zL%e5l=pLBx(&-4cE|`u2tMDB3AH(>lY7FYiG5+1y?d zFa?^u6b3&O%wnzd!D8idy@WXar_mXSccJ{UxA!I!pl8Am%xX89~x-a_fgQ z5@v#b_uZe-l^bsV{_{3=McX;P8t!f?{5!Ix?Zm8gZT;VGt7WeG1^ca{E#=L3Vo1FI zGrO@0nuCK^p;f{fw1oUBvn(DrY#}Uc74D|)_tC`5j4#GAQo@dNl=a_f&Cr}tG$`D) zwF2{LRgJ;9d6bEWnSPA`2uUaJd#ng#>y(bqH29UDZ~5BGo3Ot^+gfM$W6=vom3rRs zwBA{;=hSA+-Y?d^+k0y>q)>`3vn1?;Z0i$NxYWYx%Ss^eUym&>w1V~>jPr7wFOA4* zxJsagX1v*Vl{nHURMNLIzS+mEYd(F4og@FhfU4-Q!IR#nA=JQyckjM86yQ3UF^6 zUYb{exrFtmkD=~_!38mZ8bDF}XHUGLI{1!$$hTY%U-K`b$2o?)=$*jkuOX^ER4sV1 z7B#4B!^M-4Qtk7Q4JTsk!pny2PW#oXW=mq<%wgCr?nxeFpO+ZYR@J{5ebn|F0Ns>s_bc)$7(~)_hpg+?km>gFGds3e9?-=PRmfj!4`gtAoh=S9!qlTPUR#=M zisEmyap|c3Mw7wF)>BaZi5!(-pwy{;l;{h*4o@(2M?z z{Q#TV0$%FX=DYA!(uenl$L>XH+L;t=T4oc$YphJusQfq!lR9|1lZ^S(%;f0f7Prc=t z6v-uvv;!F)=wiIPYdE>`!=I5!X!ALDS4yK7UtCuM{G9AOOM*<^!2I)l6b@=Y1%=$% z^i~L$;A!qI>3=B#rEPH%As>!N`-dj9z{k-Hb>wN|lRc0ka4#3Gj>KGff4D)H#yOCLBI% z5X7@=Ek0et1=8pbju+OWDSR3WrMpL0|{2}ZXue5eGrGk(&FgBXbHPPbhZ+Qe% zB^f6WX<*SzTFn1N_tJEy4GVe$6oPU1iQ?)Gli)P`gu@SFSy<+qdMhJ%q;VhkR(fu_ zqyJ{X!N(P_f%D;?xWC*t!$kxNdAJ?NSvD&v9e(Y?!?Rkmq444rGavf`HK26H)&q#=$uaan}F; z?7jPU8@UZIdVkJeF>%l59oh0jw&SFJXiqkAc5|CoV`tl*e7QP$jBKs-sz!?Ky6)e8 z34jmqF{6>Jc(bi^c4KLV1VIo4K>!5Dy#8eM}UPOtKQB!VB@Pa?p(e7YyIT;$QL*sLB@H3ep2rH1+ zlJ!xx((VloQmg_jF*e<9f>&0AVg0@gjI|M;*59 zG=iKUEzY)0RNoh*nl~-7L&oBzQLmx-tb@hoa>2;-nKnEPJE{Rd7BG@({Ls1pLl>La zHD$Ed?<}MJ6j&4(lLd|5y6^yd!N<=>qx#L!&Xaw{^iuy4bzt-?yT9Pwv-dCGADCls zf;)i$yEo;iaTBGui(E$- zOz8)nuj9QTZ%&6!pnu<81Ey7GtZHCxx$@{T5tu@Sms%pOqI4w2Fs36)?_Y;hF?g{G zfsV1hK#$E&QOM3h^H@BAR7_u86R>k2-#U#o8Vq3R!>YE;*0cm=+^8{lMw?$^#LWik z*PB4=`Y167dq_Y{j)t8qfZGVAjVdFnz`Ud2R1)G3FtP*>KFO3ms(_L}_ORlx-C7ce z8bET~F<$cVMf{K}kjZ}6>(l=5pWyv(jX`q(*S_gb?)`6-?I-(B-TPnn_n+)8?|*xU z&+`7a<^6BV``?P*|8~?Fh>=X{y{h%BSMPU*{87DoK7czvdASuSSiNiGz(5~<3P{^; z#;q-(qjl3QP$V*5p_yi*l{C8<1;m*3>f?-;vC7C=pcmt2# ziYKusR;@-)$jB#p)WQ8ljJ2PUoflq#971&-O@8#cvajB2Q@?DzYJwoG=c4pe+>S7C z-X_2w+m+XS%=0CWctM|6obYtrZJ91?EEoB@gRIG?pv zXoJaXtdz7JnR+3|Um&mpZ*czvcQ6^+Z>kMZVmU0(&}M4e(AJ}v6aGg5a!rmPJgO0M zA4C*>iKbQ!$pV}Mh{^>Zb(200^$svdr35gp8sm**h>4E4hL|?n4;3cryXbe zAlzZS&)qY?xSWevuvFAU<0!0|A5Ts{y*Y~;=myceXs{y^HybiHq4QR+r;4SB!O9Ub zDb$o4YNVr>rGTv%ko~<9JXY(Uwjl%OUQ&YLOR)f}s^S;Bk*^U3?AV+P%uwp^B9KixG`e|f?G0G>^`qXwz#i-Xw zdtiSGfJeWn7WCAF`8~ZAEF0kh?YFYE#qEpKYGC<9V&kGvXxVYFmxj7}O00!l&{Ko4 zTsmoptw8LqQr?oZ7R3@55HDq~Kq2uqN`?YKowE&UJM`fPFmzv(>x%Wj#0jB|o=R9# z-|wTde)@}LxR0zvNzc$i-K7(Feg|n|3_cS&aa0$WYE4YJJLL4$_v#V@V5;ykv4#9j zyykHT{sc$7*T(9q26jZ>4h`kx8#mwhV+I|jkie4CEAWlqkSf3Z;3N zk2)M+JI)kn$7k%XFk`d8IV5ax;3ESib6yXwl2Mp%?M^zpt1z*#ozBE_vawCAX$(BQ z!(m1?J*M{7*K@ta=s5eSe*V7w0t5aIq{D@rW$>uRT`+^e*!IbY2PE&*o9?o=LsA*}$$MNnPEgA!O?V&=Jp>aCUpXo}{x9DB{^My9ploY}@I;l>PB z#k#4>Te0zqwkUgiw9$cd;MS$+TsjSn? ztgoAicNmM5MjtQPBFaU36FFz6tFvQsh$iPc`M;t*=*H}@|mCz3wR~P zYfPX}*JZ427IGC_#cq`xT*gd?bE27f5HorE^_8e-8dLA^`e*S|zCo!hU!lrRA{<_R zSt0TcMlBg%kSd<}mThALQ~-ltAT2H}&{SqXM256et1{CX#QtE4nKA;3cI*g>=`n|1+FOG!`gaRlumlJrXWqLb_Fb5 z(JP5A!7f*_p;@;o$>pW(EH9#l6(`eyn}KjvuSXSYy=mvKH|^Z@2J9?&UlT7l&<6mm zPOcyG2_~z4*}RfrHtXw3%B#V9$s{jUQr?(jJEJF#2-0UX~ENs2$sWDQHB&M zPP)y8&I%x3Z(cOLG^d)4Am+2GvFEm-fIY^7dNl>6K3%Tcd45f*k;R5CzHLk$Bhu7{&01(v=I9%0Z(!^bW_zF_|JjH5PV&FABh6ZMgSLa0ieMNg}?$f{higE+8Lvr5s5Q*fz750GQus%Ks*& ze0nHm#BXLoazuW!5m5~b3V;6X%NMoBMa#d;4iLL22r(dlZ$r|vfIj}FCoFt6Hk#%KcIw}vF+7X@n|qp3%bcbGT%_m9B_R)iDCm|QU>^FoG!k80 zUl$~4S_KSQsyR(5K_TW})5T%!rEO}`?V8?)-&-oE3+T#XOx71QVtS$QrzKZlr95Ogrbb_- z?A~^@VHgzIM{iIJRhMHqDs@?7T<|XmQ5}I2{xR zk;fZqiL@;3N~e$maO~C!@3@l$4tY@0Zt+Ah@na5JZT_ZVn-StshY}@wHbnAR#%agjer& z2TeE+0}=Ma(V&^60!SAe7(!7QC4E+H2MmO&d|XdK*oZ9(q!fo_rPqfTM%hTDJ9 zq(rRPl-PHaJhPzUq>c>Ms39ZaSv_cx_=JxHjF`^MsvaD<MOMBs!|2H23Vq>d+u715q^-Dom+1?wgW6#56!I%d3k7OLs6JKr*KzIP8|n*7zud z@CID%2@VBIa0&|o?@*$HUVU_l!M2*RY}jzrqN>SWCn}6PJv;-ZINR(RJCZ1-5t1~@ z9b!-548yAcps<&CcQ_+i@I^0n8D@$}I9ueiB|NssW`K3feHF@lB#V{J$cq0kZtD>r zEi*B(g-fY}e*9HGN|cpj>b& zX_~Z3%HBD_Xb#&|hKHIcR4T=8^zdA+_$C%kd@O$qcq}UTbW-vX541Xlf{A(4AbQX2 zBsHNCj;J$GU$!mw)Xo)|=z}XgYVQ({&;Yz^HW{OoW(6vWrmIR{lmZ}*W9XjPrMwk? z4i5e%B+J=g_zQYBe&kvigttK$n_vEQfBcIKr}&ZUtp}LGe@(UIxtaqGRUB!Ctsz#e z-ug{N!l~-aW3Nt#m$c!14aQ?#_SXRmn!S#i^E>nc%%?wLwAzm@3TqK8y7t3EGd2t| zj?JexZ*X`9?(huQ@Ss@>@*VF1hYaA`vzeJg7aU=4b@4&Uj1n&1Vj3`8lr;~MRLEfn z0&|TVYDyS0e=Y^#P+N#+gnFWhK}sdXsp6^5a2Lrk=CXu6Vbx?60IjG;`HaSfMgHn( zYQvooGb~17wr0yi`xi_Y(cIku`-)Gek1uw2URZ@uaSN42lG$*9$|{63dkl0P%dccT4kDuYTSE4x;eP z#-Lfl%SAd(8(B$uUp!$E%JIa9ClFg}rq;S1O~=ga#HiNNdOJB%=4_`WH%Kw;i!oBn zc#X*@FC>(aN~=!HhZIbXNa7L=|0EbpoGH+-rj`S$hR%Nx2z_CguR-=Qg*_`PdH}FB zGzDK5fmHCgy$@K5)~YcBC6i#4Ie6OQmSwLYDzgyUjKmUgy#k;kDoo#+aa4UvN_)4P zbHv!`afh@@3!a6#qXZr9LrBJs1<26i7fTiO(c6(abU#*VlzHWJMxq^x^k(O+nd=?T z%}?6xWF&LvWRD1j**(C31RSMsM+90ogiJ8ULdFBS;)T0NjRV)|8IWfF>G5C#$V0T# z+^GE=Uoy|5;ChhjO>la%`HBM{61~3l#Ed0n z=#f|mJjrtxc4<*)J80Pf-JGs`E}KDOyC8euB1&pT(BQjRJF)N~@;E$gUPzCkRJ^Sn z)!N2}OpAt>Ov9;=cALaDJ*f)i{24vi*wB!f3-__wj-cU>O&hWF{%QZ|PP?&PZ$`N2 zx2_N3Km7?T7)IHVPryS)B zsXBUnu)==0f}RDzN>7+wX;*7)Hx;F%_9D{JUk>Gr98aU zM*d6Ry3cXFEIE?Y2=NWYx5w5_$lF)(=oCF)`G(1I_;7DeHaqjF3#|k~84AW%sCyT! zgLJEr4oK6E?9EmaD5A{vcnC$GJqp^Lm>~@>kh7qfAO`LD)bA{xD_pmkY188_SB?yK z(<=Wy(kUm}Mc2nebare|=EfR6xRu1KI?e7HzVHs_2n`%Hzc!lY)}1ln0g-P1tO>;d zTD}d*h{QCw&;7YdP>2gb)oxFX7K6A2PR$bw9|Rul)z+otZuv zGfz)kt1?`_yuk(^YG;@*1B;EV3*n`sXqAp+O|jpT@?dk*G=hcA>>o9yag8dOL)W)P zO_eq8EM`UZ14=jGF1p>FSO6%MWdN@yp41(r%rD@}E!_D8_HbOWCSxSHL~DRRXbT?U zJj>nj8QAPl6yMcZp*@sBV?^g2p25nqCYn$VU}rNo?N}Uj0MozLtUYT8cW)mHvxjxa z-KT#0jcMMf4C|xR+L2s{VM<1FkThqlMs!$SIx%fO2g=WXIU#MBkigsmMaLzjQ6)3R z8M@hSmsqOde+jv<=cwo#m2Gn6Ue!g*I$KU*|t znj)5yrd{u*iF&HMG1f!N@1oz>8xYCI?sh;uw_Gun-^FpVQ24Rq*>IATFw4JX;@3WC zqQYaroW^kg!rOWd-t@pTN3*ggr2?IYV8O*>HmON_+ly)QPh#}={*7#|Xx zS&&{u?DYPRQ2mZ|Xs9)uy4ZfO7#~Vq^od>6viNZnjKX2N`FIZu2|10Nwm~!U_AI_{ z#AYzWR;DSECnKyKFnW`{4RfZML5@~iG`APku!} z6eKgHnV8nhb^0Sj918*D$eS2r*8}W3f4x~-(B+%y?N#IMG5CDr?kp#vk@q=Fb;n)QXeUw3)VZZG44}YD1-BL4#GneO!0U`U zxL*p?(}YIARZ~`qeEeRu@&`_HrCHetrH)E-5ieJ`i9X{|Xl#&fq13;zH9Qzyj#lJM zpZ4K-3K^PC(nBvM5#LeT5NNsVW%5$Gu*PcxQ7n0nZ?dNQ<|lo)O(~)@ ztQ|UtXs6X+2^iI3Tou;yb~3Ivx`{Q`G|sUiN=dQ#cA1^iQOVAXE5gZ!<`=c{qN$vm z6w`}hUlx{Y6{7^p-R3~m68AD_fVPhj(@}+Em^TGdOj%N>Q9p<43CWX*p8f;CJ{cu_ zLG(YN{JEt2U!~xeF0t-I! z_#J6uYktAc5~4X33-D0?vhEXY(!pZ-!B57SHOWj4FP|fqOY#)Ay$I>mK6BymO-V-4 zU?FElZD1~QL@LWfgC}?Gw{;llaDj7KD zhY>PoPx%2XkZ8?U0PCp^o~y=AZMGg-sDR?3;oNJfpa6HB&+Z^nnZHd|ampJPlTgWWV_a%-)|9al-D97vLA7eYbw%y6tZ>t@J+rJ*?)v19xbF?)N2yFRM# zj=DUrkNX<7=?itu%KPlOhY?KXbl`CpRtDDsyG4y(O6mJ}x&yswOmlXPoCyd` zkC1W}Jiox95j`W7|HQY{Ip!#K*uES*+V^9$>a7LQffAkEq=60OB}bcwZKuz3WsI1K zS0%ExM7T2=5^{r?sj@gv*p`tNM5hxmSFCbRM9%tactGh9RizCmLv|YSM7Ngh43~_eXx@yN&8&+4%gmB=RO_n}2pk~fG znQTe~HRA-bf7}hSv)~ovKL)xAN2S&t31IMlbc%NhM?Vc-*v^M7vy4!l*Y>23cf6*u z>eeIoz8a}A2qgfHU)8t`()Mze9G~x0N`_(+FoV6v;r5h-9Y@5A>IU}3@>=q$=5_Ys5i&m zn`qEaP^P)5cIg6R8-v8kvYVF?ei}xY`Bzk=c2JVWKbD;PVRROEdBaArti*mpb!r8* zJDqOW$uI1m_k`r^u36mGXo)q0yjkms3LS?-!|WJ3bLur>&PD$YyeKmXh4?X~=*t<4 z>t>c(-VbC2&f>WaS961GHzPk}v7Y5P%VocXGN5Ho%1T@nyx+lo?fY@O^W=(C4TtCf z!{*&XkMqoQY2RlT1`@%M*2ZlZ$f&)NBXEH&a<9E`W`TVb!hNTJECGN6$MEG*&sk|N zWklZe$r_I|LwGoi=1C1s&@^^A>H8rm(<)wIFoU2I+;xW$aOt?yWU2!y0BD4xLcp0O zsTV{>)MWLTUt%B!sF{L2TB;G39XN1Ag~a&PLDGFDS8?1O&4@s zU`4!JaMJJmbK(a!O`SrURI!GqcQ8FpcDKEKOjaXnsz*~`%|N#M&qhin?!3b5VinES z*HI!{JI+9b9bEwpi|fbgng%11=ef`Un+pgC|2_xRV_$32r)Z4%$J*`}r}w=?$3v1@ zWplI$JC&w}pbtdPdrPpXH}Gg&6+v~k_}-w?2PFi=)~5KHjK<-cbhN!i-)iCM>((h@ zjO6B0O$^j6Ja{+wwRd}0c2Y){?iRAFnB$1=lB?ht;I_wT=GZp&q}5J+i4T1$6Cn|H zF6f~^q3ysfM@CM4f{TRDMoF?pcM8|W;yX1?ws!Uus9}CWif!}jFbiA6laQW{Et^-{bSWrT4xHkBNF|}J z3jsBI?K0Rl(vaOZZMgA0yV&WOpng~pA| z*~h$I;c=YOEw5vC*Q}BC;+b)1T<~ya)?;j&_h(+%b0$ls9+$&@yodAYfgnO$t&d3$ zw_UwCxkD+@ulEu<2lBP|=>J*JXFTY4JB^KW)ZA*0ZieH**4N(FVA#ZiBb&|PZ~<*> zZ*TAK?M3kS>HZV^yS+od#b@{F)9p%B*?sbKdk_BGkG3n~(f0onZ7-nhsh^1;^+=#H zOvH4|DJP1x+d1#4Gm-xL2l;GKM)xzw^x4Ln5>pU4kXI`@d;c!_sXJ(1HZSU(e)Oi( z7}ZBNn-okJehJmvLWV}^pgq14qU#{K8BFlvl2Ov?K%UA5BvR>&;YO4#vC{Phtxo%f zWHuy%XeA@KPbCtg(Mtgf`0?|*PthAl_CJb#hI7UBZuDW&5OP4Y+f0N|!z(G^NqT{a zNe~{?dCwyR&~BqTgX4-X>oYf(5?WjsSfHF;)HXjpzx2czg2k#V?}H^PgV7d42W|xLD-X z>$7(!r>D`Y_aCF@(TC?B&tAXy^yc};=)zLkzl%BSrV*C}}1_%WT2*n}gv^;c=yPAAR}gZpmQDD0MKb#^d3^ z*4EY4)#iDBvN;%?Z*>V?x>c1Jz7S}PI_DSTXh+DK4e`&PqqC%&oR8|g==3HXCxZRn zy!r5GZR^pWI{jvMB2=(E=VmzYzCb@3*2b&ke zp<83nA9wl_{hqqjq>BXqi zzXb19yCa?A$i^%|fW^rI3Y!M2_MA{kH}V}rYmM5aj=g#RbM5u3_|@~X=WoiDGIVRz3c_`bEaLr46m)Hu%9Tg2g*YzFHJd6gv!4T!t&J*mgG)hNQt- zfaERN)^5j}^}(vtyt;%*367QxO4YX}Btprajk+~@DXV3jBVv3^@spdI`9M`5f50PgLoDLUZ> z6P}3LC3SE6)Fr`y(Bxx}LW19`aqP9tmlf!a2T{m+i>;@-6KwiQiF$!~kjIv+FH64T zB2f7t0!(T#baybgoD6FSz__J|dOWQl#*`YHAkX%TKCCk4#Po%>-iS+5(iOmRNB$ec z^z*yvaEKwLK^(*FD4i1I3gdT^yA6E4{GtZ&IIKK(uFY0x!j?IgAlHRF*QB=j@Ah zZ9(vOA2NeGt(JJz)nhsr#j+#q?$j`Cp`Y@5cc&V|U64W^yD*_Ojg}k%i-d|svXB@7 zh}E%3-jb?s{A&-4!b1Cn8DUYK(^T>y31o|u&_-GI&#zBEho+a-`JL zR?_scy>gb{sA@U_`2sz3Zp5(1VA4~xd3eG*-4LjR%7s`5tJJzlKQvW;2izGx!45FF zb8x_Z7{OihBzKK41dWAsql2i|>C19)&9F)AOim#J6N$tFz#^V3lP^ds=U8SJ>UwasTd3yp@ z0pOpnn&A434?S2><9C-abL1!@yUvZbWS^Cl5UHl{_Z;nPyIe>|5G-D#M>(nlP)sr< zr%Da>JLM?3PMSpa8kj?bdI3)q=W?D`fEhe;&tq96KR&kBBohFtpr8J`%czGmt40!$ytj{)M!wDC)Sh+J- zhs26?uHO1u?>CcJW5MJeqpiK_pc>)}77fD;Z`R6W56it~Sq>@L1T55HV64zwRfsNZ z#!knX&J+b=_EdT8>hkbR$AKxIj^~~9X3IY9gZz?WbAMPN0mNI1iTTAufeDW!{$ose zK=pf{^snIN7Hh`ilVa1|Jgbk+0_4OUwb?dkul@ znc!=VBr!^~0us=cQIpmUX1v$+*K^ByyN!YzP!l@~k6&v7IA;Szxgcv48U7sZnTs_5 z>#U88Lbg<9y_s5gCe~850D{LPh1kq%_r9!UZ~~^$KZ1;+A#h@HVy&)Pq&wCdK!bKj zJW7^(;FVJMHFu@dnE$RTrN$y#q0UvN9r|aisA?P*wVb-N%Ue!EJ!HH+b-PfA!@kAp zo6*V4)mN1dt-dGMwze&P-*e@iebo)`%FF5wrkbXqdJQk&_kZDnEFXJak9D8FizT}N z+kE@wI)mN51wZ}IuHyIL$M0dCM?PJy^7bk}r+JL=Ia@lj*LI@)gRSiMS;5Pc)zt1* zh?TyFwJ@TAC$QzvJqgaxw;!kInIapfjS4As0aB-9H@jJqwZSAz5?xzlt@V zWwEA9XU25jmb(|Snl!&}u3q%w*{pRT^#!K0{DZKg#R#~Tt^?`|B1gT?wvWAfdO06S zsOE#S1vI;uWpw&HzyuC6%??)Mn-e4`*cAfbLhoqeJYurFHJx*clMumuA9P%Yhpkpo z+KS>(dNxA486S||-y#u2F#m%xkv~ZOhwZ&eW!ugFu>W*tng8J-KFjU&Hg$X$_wq$`bV<9FJ3Z^z1|p zRk!M)yPQ0FgeP9CYOuKXZfbVbLwQ`;DtT})O3vYq-w_pxUkqBw5HdU0n!_MUt5Iug zIgDGFmmE(%$pny~mN$p$ox5#6hZ;tVP@@qE6Aq(D_x-Q7g;A-E0(W4g)7-oWjr!9w#rc z)1ywV4yQTHoaVR0+At+>0L0rlfYTtB%wgU+NsZ^-@cI_GipwFl;F?y9_!*Zr7JclO zr32(YQUP_AJ35eOjsRVMBFudFbGi#3lhP?yEuyyKpWq5&Qs4-re_SgBsqm>p>r~b^ z%tyBTJnSc^|BHu%VY+#-pf;xH|CN35!_oh@pH`Oo|3iG1`u|e@U+VwU^#9?ge%`A` zgFYz9uA<)T3iXvA_CJ(agpGnWfJ5+U%*u%MbqM!@|K4k9hW)2Gh6P|T=AS9@|LM-t zr(XWgC;LnL&x3rH@_#A+m-4@G{!gAZ(=z^a2j`waXpofxRLGL%2ff~) zzt!lRiydCZOK@uR#~wT-lbGyZ$F&E;HZEE1f z&qVUYQRDOs=z*jlESnce^RkAELc2S-ig%11sM)ZH)R=T2L@+i5TGo3u)`p7B#-_Y* zYLogyr64mq|#zL`ClE5BkJlo-xMouO9wQXY?h=jfz49z|v)Z zXuHEYcB;0xVx4wWKq+gzs0ubRfN+3NLzvc@7nix%Y8>niVhJ@4P=H;zT#Sv)g@g`c z!sR@R=F7jl{s5f$fBQ2`({Rs`U~9VjNOQ%5@+fKzLb5Ams9id=8OpTbNX?v?+8w}^ z(Zext_2NkK=H>ejXCF^qJq$@Cqe^D6GC1Nbq{ntGcEQ4-H1HQBp;t6``;Oy0C{sclh~s{@e98HNHpm73qDu=F2@nU}nrvAY12e~c{dMVTk4qi+=G{~H+2Ni$f~-G$ z`a#g~hu1%76sZj5!m^-LY$z*Y?Q;(dn^3&$?(HnTe>>s+RSNX45aL3>Eduw`Pd_~b z`u3h%2&kz-@Ln5m>#W0`z?rkx$|n?JuUAS;-u--HSAvcrH&L1F4eYKKbA3w=DosZw zk$>4CE7Rx(f_koNm&uJep>1BGl)MdZa?4R4N9m`|m@Z5cFyOb93LX%Lr!qF8H#+gjf7 z!|?%WOh^V-8zzb|TSi~AXAU~K>qh!eE`Cc4JiS%2Y+l8wii^S>2eo3+_VpE&GwF zk||*n*ol2(nY6=XQYA+w(RMD!e)dNfKRfpkKb8B5A7at}3dxgW19!wt&Ze98+qr9V zIpQOGnvCB;Nq%x4B4eb5Fr{jXO0pF%J*YrXDL3^-FsMBp(%W6Nls;M<8!*MW08Z2%Ws{N~4ywq>&Nj_?5OAbGRO1An#LRmu)c-SD?qvp8I$1^DKQ0bqz$7*S+teXG(|$dj~JA z9*X~s7gM?~Lsn$y64Zk5_JDN7FJ?2pQBC^kWR%pfv$3)jWZ5j#mVb(IN{Rmbo!S4K z^e20lmjBHBwOj)pat#<<)<7iCG&rH_~gpG<4(`I*LrEf;{_QZHiS}M@Ili-UmYno2!RKRrM^zdg^TZ4m}=X!eu!< z95?TO=Y(9On!B8kg?uAfN?z_fooOAGy9Kz1-dc^#APp|(QK9aF`)UCzY|F^%kmK}u zh)&JZpCV?0@6=~!s=Kp4)~-oXKe;*jT3wXZP^ zsOuq5?X+D(AcQmoCLjU|+X%z{ouKnuBzyHm%IF$ zaezYt$hhj@j$j(uWUSn+{j!Qed{$-+JELZQ4hSmn(hLyID#s9E`ipcErhJ%s3b_eRc0Plua!as~hw?w%+cS9i2W(dO4Yw)`+deT4zkfOR!MKmcX z%}>f)EzdSh!LGE4d6zo>5*@nJlyOO}<0guPfx-&XPwGyRn&2WbORVIxaIoQCPOzaD zu!qabhmR+}qS$|T^7pgAx^VJW7SC5GP7!~NNzyT{@_u_LKau{1;_5Cx zL!1X+uOD70dkTWP2ZNa=YT?R6DB9Sl5E-JFsJ&55uI=?JKzf)CjH3C&$Fv1+$Pkbu zwQ=ZSv*H!*b?CrB^#4)iV58Yu;bYk%Z|C>q57@oVswXhqGZh3KomYIBHb)BE*BRk^ z#UnQEd-(9x-}Q2)jso0kS^0pun{yWqw@8uYL(6L%;ykxPZIF&&YGR|>s*me6 zB}>`!6ve<)ckwrHO=y1coq>yCgK6%(f;;cuod>4+k&2D+LwTEEjNsP;s;u^rplk*8 znSoQhd067@1`$YHa|Hlj+!%n~KGMM?j-cf}GOl;v2JlSxvxr%5=|2hwM-KosK-Y8)PvRva-+CMgp9 zfn*3F_in#{@x^65hub)NWvO*RhAT&2vKe#V?n8}2*iZzRBg@DOo1!1Aalndl;ROm^ zB-imE<=aPDuk=HnsYl(M2zMsBM9#kec&3RRp!2pOv-*8q!7PL88eWFN=0%b~k-^X( z_ZnPFvKVDft>+r-cdgs!CnU(QRnSE-n2*BJN;b8+NAbV@<*U#@_{%ni2RO*yK^$B}#afG#p!*)oU+ z6fPy7hEh|RQ`O=EgCv=;3tV;b6W#y5N{bXUr+<5W_Tra^R$2-)elMlv5zE9>Tg0L{ zRbb1m___;2K`AgfqLyz-sg^5gEB6t#6;IYyn6RBLZKqEBN+~p>r#j$7#iAl?79{Q| zBiKeKZ?9#i&Z8tD-!|cfN+B|9td`~H`eS0TgQ0#;4NsYcgei=ZvTq= zx&YK=9@;djoqpWAgl#@n`kjNvE~lNjpErce#2bF&xGvZ zE_HmwUOq-R(UQ@~sC2jl!%`ASz!INE7^OlsL2ILE=cG3+gj3Ta@&#^WkD#<*2)w|F z-4riyxs)cZ?d$g5_O@8B_C;@Hj@PoAMz*A!&;?*s6fBvSQ$tg^KW729BY~-ee3Ft4 zxKAjQU9cS0MEl#NS=!i@ZG4!mk;+Vs>{%VjX=0upJh6K)75Z$b?^~$(l zai0!;cPe->6_XZ8U~Hl;=qdhIB$w~<7Fa}#058}L7pzj*HpI`^Vr56R_^eQir`V!w zVfx1*kMb1~bpT+%Pl#V+Q_8e5Yo{a`cZ!jbqPG{&uk+$v`#G<743GSd?#R*GDK>f^ zPd>bP{^F!)Pv;xGj|mEP*4!MU$neAd$pPIhHlVU$Z&2qRHm^^)!BSi;day zmoLBljC&5ZB4bnYc1jM=Ua#3aNg}b^qK{@LhVO_MO zoQFT3$XWNK;H(pK`~hYi7nO7MO3u0`1!o;eu7{a*j;x%kdvdBhDLB<$p1iSDSc-9( zf3EM#<#oT<@+!|G2T+(@m)@6s-!IsAb7XLa!40L5oE1+gC7u?P64vR)xlpwZZ_cpg zQW&l%3p4QLJR+G#D$*qIeSv|6b(Zbn(~6C&7V6&|UwnZxn6c9A_g&XTo*Y z#ucPTIT%|wFl3nXY0i}3+>*czcDoxRjVLHD|;wR{dlr+AXsu5 zd_0$@dR0fmCw_Yd-*!MJsuUH)4gs8)6R8yJ!fMEakTg-;@&#MX33HiY%GaOSQ(mk@ z0mB;)RFP&$QRS~Q377hxy_SkJB>r2Ot)05p4g~%cXbKn>V+3but>LwX@rDJO1CGG5 zQ`@t7wW)ZuvHcBs)p9x)S4*TpuHd<@gn*W|2+td zu>;lg3yK2bL6|s{7_D{)=N&Le=GWf4!Ow#2Zjp@mT~t06a;ROObjOEtc3Xz$7`~pJ z0xKY#g@6;4_3;QH?ML;oU}H7n!J1BtkU^qs0lfPO&Znv=( zE9g>-zw+w?&)H96x4?b4P4-yHjyZ@v98LNV<0ck_e)HmfgjZ;kJ+Nhm2%({Pg%a`> zo|!AlNtnH=KEg29@#v=3j$f^=M(vVV2562%8&xqL%`QmnxUC}EL{S@8d8zH4P^!e{ zCyF6$nG%u-{Od%W!`6Y;r-K6`!H3f~uV0+RGI(+zR54hq^h7Fs`ZgA$D7Z%8LIeAG^-FZC$Llb< zE9Gs$e%DWM{|6C$7mI6S%Kopizqjw~|MquwpDg!(5Aj*<|Cal|<^FG${h!(X2}vnN zb_gp`aO+2FK8vi@TOjsqErMJ1ZGe`)`F zkk3;7FXjJI{!f$tTI8c?YpR`Uu9;eF}Ct|KXrN z_8yWa$bFbJCg(l^gT8#`uT@jlC7GoYw(U`%tlZF3>F7B6{Dr5e(~tYf6|WbsoSmGW zMK9jJJo)haXNaSGAzlsZ=ZV-!K{C1KP#?*Z$Ci+?cw%Xdpq37`TTQH*n($)zvMVC- zvn%Sc@hal@WLMO~=T#(2Yp@nEuHwR_{md4H$re>+bqPrUvA)9t1H_aL98{XU zb<}Kt?VQ?MzbRo;^az@QC&=)ovE7}GhL{GbP3%Lb98E;y5CAoSe>%|21pjFqPb%U; z63{6grUfNE9RW-tNoYw3;$zZIp@5_4JI0mB{0sx-RC zWU8*S2oey0cMMYiQ09g*)sE?v@{3VganLSV^H&V1zX~Je0H4CG_kSz=)%ijtoPY)k0Y7Q@Y3NL5|=kl~- z;tw(%OL1mqHNGpR)`?}lC%)E5{SK@h8h>k*q`PpuVJGTam*oT*fx+O65Ul=9R#e$# zH~%q6c|A=!hyW3Ojm?yDbXuB;Ous?^h(js+LZN&TiTaD9QZ`&0VlGINT?h+(*JJQg z=RBWPsX#8PQjzc=uj1oacH2N4-UnoOuw`l;F-TX79P|L#X#n~3F_1v$ z3Mh?OURqi|w;@!@_^==&HsTN#mAP1OIxM$Gav-TolY4cEaoN55#QAIXPRX>iCc~&8 z^Rt*|9QD9Gn?-g!3u5$aI+?Asr-Dw;VmlG)JZLep&yJU*)Wu*lu7YJV#;*Zt@6SRX z0f!?ZH-+^S51m4OHPMs+bM6R~xSD*N2}Dj*5HsnJE3N*xk1 zPr7643QQZnX~dV^od`7TXY=)&4Zv(2pDeoLvn;2(J8`y91)Fy9;TE6@_IeM7dw0j} zwQX!K(CcaVWr)Yw5FI`Qrs0)ev1Jw93-=r+#-6kFfAYWs#by4CBlQrdX3nJjy_^x+ z-!?Ot{VyrI5kuG zY6~5H&5^z~wYo~@QX%OSdidg2Qd0YQ$Vd%u+06`(xb+7B2te3LYlnCQ2XrL(EVGZS z9A{QkMvq0?ctmHIfrnWY{GKV}qKDnIUV-&*u8z4t{OWG~MVbqJ8o8I!`Q##8U-iae zN`)CfR|<4+`oPa?;KB>P3YfKA6O-a|F>mtN+?E+ZwT!_YnmEe9zG z;JoY%?mn%dOJo{C3mSdBfC4`XsY6yJozl0}UL(=k@gHGIZ#tnP2ot~6_i z6rR{0g{akSS>hI6==_Ym0)S@#uVr(ksR}C}1noc& z&hycETIKj7BI4Hw;KlG7iqW+z2M88#)({U%w|AkQ)sk!P#y^s|aGi_qEq#p7qksQf z5MDsv9PnLSMJFQ*OCd|jCjV@`J9`2;g!&<`NATi}$Y zkt%ZPl{ump)o5_3VX0?Xg->Pa)GB^DrTnzQVh{$GROtQXEfZ06Vi^eh0m9BkbgA6P zof}MKxixN^QgXR*)9v2)e=(T)5BLeje>Vo#4;TNvy}MKK;=lKw?l0rNAL6r&|6ay_ zFXO-GKL1VkmSMoQ8<|aaXUYAK){1@_Tnj~xR3d!&qCbA$_$_IYCexeXi6**U@1zgO zU+~gHTbUFV{JCON!`ttgrzp+8!OyKZQ-&&`@5;7e)t`Hg8H91sJxIirsn_I zarM8adpmne{qG?@OZ{)D|1I^unex9DN%LdhwQ6z?c-O4{-s@n#{9jBGpnUniD;|3J zzr~}a{C|kgQvNUH|5E-J&i^BXV|Q@wo!t)S`w=g~>49v+fqe>`C4ccM>3bOh34FlE zXl{K$$MLT{NPUXgd1zz&>)YC!_dmz*6SAK|ahQy7bIiL>Z{DoH-Ygw&R3YIhA{du8 z0bG20=U*qT8|IRF+B81y8iV=@fU!e+*RhF2e{SJ ztNO6kX>%N z-RoEQ=Jl(0@6RZRhWdvd*%}JNc6V?kfvrasEQ2|fuIT`vB!J0V-CBnj0I6gjAIn8t^o9QB*By!-^T- zo>+8bJJ3xqvP^o3R4mWyseY$vj;|PWyufcN-7^SI=0E5Fe2Z3(qso(a3l$(J=ykSqS$4S2>2b0T&n?~X>P9eTvI4zJn z{yL340;HIaj`Og}UmucJX76chP=hd;K}!y)JuYm~lCwV~S8~@xPz`7i5{erwZLyB? zk&E9IWG}%o{@N#3I^8Z)82YZVU^v(;MB^*H#z|#?CrTjqfkZ<q)yag4~hcc!+o49`T$(CNvf`)E}O|_{*!;A5YJw54Y9*LZq5)=rt-2KKw;`W({N^ zCLsMS13PO{+kJw&v$PN^#iDYGNlmd-21{wtDfp(VHv#T0UDG7)=E$;~#bsVTJNf&E zH}7BOh?F383ys7qJSNe2F#ejQS5zi-b%8MXJFV-Y8(iNMz@8V|U4T9yT7;b{zSaz> zHmn$l?%a^1FPB(7O8;fYdnjjmz@x=Y3c_Sq zzfroj+TR&wl`6hyz8rb>Gt}dudNtZMmc8H{5~W<5608@j)3Z-0XW$k)vHm*$%*tS> znV4|SS(d%C{07r(o_=YSSQ5e+R#+~qrMOs7TBY| z=5+~O4q5#e!+x43Qz`l}vbwcd*RRa-dJt_?-n_|otaw`5y*(?q1uNuQG2NLy81;0K zgYf40=~+RxDodXT-|}x%(Xu`rZ7jaP*#M3-M%u8*%3qms`bv^utWz+Ddo61?7 zzr9eGRzu!}K16~ftq#Pg)8Xk(3cmiRP8b-CD$`F=5p)cU7mg-GW(Yyun)HVDxH%^e z?>%zZ+JKr9|0eZbG(hcUkm7)OL-<4a2R(%9CX;kiRE@KpC%bd9+a5#O>&fK|Jh&U+ zLH7Ofe~BLnwH*&NWXD{*c7C6EvLnWN#(AJ6Uj zG2u6e+OR9WUJM|Q1?8F@Zf|z_m|BIPyzYzk#M*J0LbO&AZ(r}X%9v?IN8gm4_?=Se z5xFy_LP`jd44WxiVL8*Fv^&>H3xKq@#X>7MV2`eR5HE48E6sRCdJIZs%OhSKawQY8 zG@~fUjIoMC-^qloeH{wEGzk}ny_*A@8P^^7WO6Rv%3fwG+O(=#u#AqyTX>S$g0W@U zgP?bo#T(hrALhThO)%$Z@kX9b?MX&Eg*#;CRr?vt3DK<;?YOe109XoU0auaWv|Y~U z`&mKmNRZ6A<}l-o0CzP&%ViVd@L56cNzlwvA7blS!9I~-xxq8c%dcgE|lD_IOY zE99p>&OzXFqy9{BF4!~5zU5>VSbvtV{+b1hkevl&T~SsVB+9nQV-`>i2@0(SW!Ee* z3#6u^8E)juuBl)aP%RBg>~qV`K6(Z~btQpdX@>~X*RNKjF}NZ4BKAUD%TcXD_c4{D z?b0kQRlJrUDz!jkGRfR*t?jVZAVhYSepO~_Y1eCMwth`-&8$uhy*hatN?+9P6o=bH z6DgV^L23lExPCh@MaeHmcYW|I*WT4Bus? zsg1>mqFgVHJsv@nHs!{fVA;*zJ<6gZ+J6Ki*OGekBDM&JA*X~Bv=AL2g$!*h+*N>S zP9vSJkQ-S|m;q`e=be6BI*i;=IW$efptX_s{BE$$czs=w-?@P-VhxC?mI|VofxEMM zfXGrAo39Eo)QewEUi`&pDSGK6fJRBk_&1KoIU33$g4O7?8qVRU^HtFKKp6-{5#ki7 z+;xR$ITDH!R6T^8Bg>Q{?k7wCJH_X!(@hx+ zN^b{u036W*UWE)}wb5Vz5%-h+7$I&ShO6j&|Gbv?9ZO{Z<2|uDto4I&(iAi3ARE@p z`nWFPbqDoUt#MNmAm~u81|>AEQ3rDJT67*X--sH?DEs|Kft@K6?nQHy2*Ch>oYW6^ zd~ona%+&7NdU_dk;ajaIzS7lgTwyoA@!U0?Ne8s2HivXubekrTv(F|!3Ed4-2wQxW zVmXT?P$?q@9gasK)>NG!RbHMpgR*M=R4LWn;k_GReIc2An7T6dx22J~!*bfM4`M}MPK8nRRB0V7vUJUx< zQN1~S*?29O?NBDSc3!E_Y^Iw8Dpyr))oF;26t&b(_w~mFbZ(~*Jv@ZiL{!VHcHRnB zM1}0-jp&iBVh9~j^fyKI1kJ)pf6|LgiL)CqFK<=NvQ!PDJG`*$mVSZG;ahoOjFQor zw)NtjRk3^;t>Vv-v}_&*>eH1Pras=r5zD91DqYTDtF1n9ZJkwb74-IsY^Of8;C)Yg ziS=%S*a9L+J1y8`sJD+yMrwj+8tErj_=rjcu=AW0u1aVRZ#BC7S~?8bc}Xz@7&RRo znhORKsLR`9Zu(8yGJ!;?wHh_1o}12y=UB*os=8PUlM#r7udt;~T5Ay>;pwc-m?29& z5aOUV9+J98a3+YwLu&Ag(-oz_qNs$b=qxj_ls)anOId) zQ9>+rH2XCVxTKT}Vh?lJoUaG(PJ~R56;4RZ=)-)HRlyRw&S1xwt zbE|=w^BY#){D$@)i5DBy%t5#dOlr|MeuGnRqj6I{*V|#`xnYgf46Gttf+*2zn^&fB z1MgCxEb@!zMDpoX;{y?%476Ig?*eOKsJd7Tvtirg>>`IgLWl4+N!1?Np_yI91v|d( zdvh+Y2Jj=*QI+bA!DyydrdO~U36UyuqGzum;j)F+6OtM=wNy?z{qg>uSVQ~rw!PZz z_MH^wzIFl*O39r{0$}3C7F&jL;i3=KSqAB;OJyW!P0>`y=R?!1y42!GT}+Kn5_mgcNNDTA4FPBcPfLxP&cNbiK?KM}02G~|(-ZSE;~ zlF$=>Su)QTbiQ=ck3I9IGn1p}Kc+1H_Czm9#==^JSD(Ffh1Bfz9P)<@qX?)9oZDwi zJFJf{O0L3)+ZLlF%qG_I5MIVd{BM5p?Y|F^|9_|QbZ5uA|7Cgq-@|;C_TQ!bcWM8f zCI7#1j)iTl<8JLD=?X10%`mur6r4Zk$?9U3y?pso?bGQ=?c@6we>r{mlV=?MD7u?c zdw&vITc_ z>j)GC(<*y>=XFP$MzgvTwv{>^!KctFmCo#lwzOuKq>gw6sUyZx3s<_smFodhD7-Od z#Xy0B17owrjzGMxZ@a{syR}u)Pa7b27?#}s!U3e!P-g^!_3k}K#SSuffh6fc7H)OZp7e#OrjV@ zP00yLWzgK2txgmrd=<8$pFtmojG`bO^v%?n>_$d@%08aUAJWh*rmArj1fe?q1I@{g zLxZ61X4fze4&ML8+%uVh(%Hv<)IOe^etL5ji)~-4fm8#lAB3OX-kEH9wDY0^1<(eX zSE^JAFUi1OZDt6DXdSXsWFm@rIpPneZ(hGRi77G4>pu1#!BT1ps4%Xd$1BP85QEtW z^a=!C0TR*#G3~=4As2`!|9vHc}8Sv9;9G&d>oR~l3AxW60(W& zmO>&gT3wA|<+fpug@ja3Dbb8HH;Vz+Q22||G@0kKVUB>dSw^!m+tXulWnx0sg-cpj z;ISA|{noPuAhpFx(-BPeucT$yhL?&VOqr4u)Hxi1u`E)rQ7={|&AzS_BMcwZX6L*Q zt9MwCgJ^=ox@d3$%IJRRD|;kiIMal9hJ3DMe%sobR$6nIbNnSs?gPwMumAq``7;I@qXA>lJt)A8fmnu)bbNrO)aZ zSq~)+bw6lSG4PN&Bi}&KK`Su>ngNz|6>8WKx$KCOTGT_63bGnuJOsr39y`oyFVNh< ziYqL7;%}+b0x?l!2X@kThdFa`x=${D#i5=UpIpR6DEdzh3#bSDy^Rskjf-VGtygP- zd(Kpn>958qy(pFRw0VrUfoRK;?MSO5O*YlDtu4sWb@K7!`;W95z5K_!=Wk!Xh&HOx zPw!u>9P))M?5~9Rt9$4>v-J$WJIoW8Q+=U`u+P)LgY{O6)JvP<@JeiY!61v2fP29D z=>&xl$~TloKxiG!A!o)= zV5dvo>Ja8pRyeMoW>H_{z9(2x{k|o*xe){U3wO(g*(MT?L;HUP^gZKhGGiv`N>aM7TFsHNAx;x9( z%ush06-W$HYHJ8)?v|8)*O}0_cbc(Ob*Wtj6=1fAmkwDSsZ-KPTT45Xw^tYiVkY~+ zOrbhBoUi~tW7apOhf)4Xk#o*RT+*%WgFMwCBe>7C?;9z=K zhRmGnK$EA`jn|kog_w*8pI5)IW9TKO)ILTJwGJX+=fkb%da-6NWsHb1I9PAJ-~ml> zM#oTmr$ia%pBP7r(Zvj`$+O|m1dD8d-5C2RXK1|-2`rJM(V(A17Fnb56`n(xphgYm zy>t^C$M5m=sM2A4Ul#>2a7)Siahojsr`I>@q2(p&@i4CWOk0_2Rq zOH;=&?sU_BeVAT=fm=Kki*cG17!eu&qLzV;YDTmN6DE)mqX6e}paCA6xfjz$nz!di zmrR{)Jg!8}YPEDYYIzvI%mF}7BXWJR3#nkutQCuiVp@HUqc8v~k;vmYWVa=0y-+5S zu=bL#)_MIy&W!0%Nr*;hN|db-8($3xhJ=zrA_#WJQQ=WfY^HJeC2az1cPA7wd*@C0 zh`|g@ojlO|ft+`iQ-Dc3yDDeo%pFs1I2A+dv4b+I~-Fj0^jHJECI)10&+elR{kJgts}_!Wn!ka*dnvNr=*01mH);F)*PZ zIRP!`NVi-=Bk-bwa|pqcOI?BkAkyRJv$H!}X^ML97}P2g04ZWGbP$-r!x~}-vA>t`a@?&^cu`hxnH_!R28x-V>U8hN zq}}X~nZ@(gIY4T?jb+%x?v5Byc%@ENsLVUjD%js(e@O3ZG5r;qFdF7!dVQiG)s);CPLk&yCx^9^<9lg>h9p(|!@B#zn z;o(yB?vZ!I(iI>zY4rAFh;{PP$RUdH%#u>{mYmD|Bx%(!)sv7$`bRBh&u^v8&_(Ky zfSP<_NVVXp|3ats%hAa-;`aiaKZ40tRkp5Llb)0;VRmp}#jC3DQYCU(+^OU^(>?bb z8@IlrL`f-F?-&gDvOz zWQ{VVH8tDGxOpM{%(YSd>PXk9Vlp@l3D+VXu!KkWOfq36i)*qi_;cuYjQk^gv9H&K z%h7hUwI;}n?2Lf`Yg?wf4BlosX~2#Vfq*4#&~B%R%zOYJ6AuduhMcm!`ZcZ}Uo1(A zIoHfugCL<)4LC6h2pB?u66GEV!E6bW?A_%%v8hb@g9+$70Ai&S5;)oEEXfX$#ja z*b{hD=ilS`_Bg9l%Ggo2pQSRxb*7I6T$0g+&fByEHR~!eXve;iUG;_)BXf`}%+wY# zPlXi}Ry{Czta)SeAxbqY>qHCYkLcN85cMX_3uid**zA`hiNcbG5+|HYrKlfsp@0ny z>wT7b5$RC2=PDzrR0Ub$0|i$X$%%Cq2**silh_4S0)zTEEuz=Mzt9}6lb%*5RYIJ9Mol}E8rqpEMqD2|A*`(OCh1E``SONV(KJ`ZksXj=MGtrb zMo)w?2;2!sF=h3%-`Y~VEvs1J=*JX^p<1>)|7HhHb58EY?I1I9KvB4voHSCcIB1%+#n;*4x!ru*yL_qo?V~klV$%m>8tPG#?Yu+4q^+Ys?{{nkWgs z-%iGmdx(~CTsX@-Z4}#C@pSp}tyEQYa(%rA2&C3`8n1QKG1p=kP$R~e$C8ML2_rM) zWal~0$ViSDl&~pz@sbc|xlOp)$wRGK&Ap(OKvLEqY{2R-K9%OMZ5NNXiI^rgZ|lRM z(C>d=q?Ve}@}oXk`d`S0Id2?DzW%qnSE;!1A3HnS%lMB6`7HInrT(|n|7MK;C=%dt zzs&6_f&7*@_E-D8C(rQ7H$BQ8i?ThdRHl z$+j+!_p$`Hl=-&LAF8KU0_9dat-%pObYVosD9~!D zkZ9z11_=Wh1mcPwr~lj!&_>0a zfJ3s@t^e!Bazhg=g0QLhJ%DK;QR`s9d{cPXwk5r)HcFU-fgB2(G>J?D&UMYkiNfG* z+78q^IbVrQLrsOVN%Ol0&~)LSvNd4kxus|_!~|Au3zW5*d?fO`W*%BNDEAur0$os^ zb?%Mam^tL2AQ`YnM1?G7D?k`2){H!6{-T`Tx{}y(9u@0=#GRN*Bl<`NazUP#4Ah(% z06tdaQ7`#kCCRT4v)SlmJY=Ll)&h1%#pB}n58U4t{ zbkJ>OVX9scrogH$rm933Q}x!uRJRvfm8W2u*1smizmf?hw%+qt#apWRhNlr@XFltP z)(j2in6zh#UMBDltxuAacv zPG|uGu}4UTU?oa>bsL66kS!BsyMy?{C!geXOh zrP0-({{!SViSPg|jm2DO<|epVlf+T$1Y00jin}Sp=w39DJ9Oq2ov%p~_L*!SBkj<)UQUA>pIJhRxrf&3y6%-$YK z4wcYQUQ)J~Jiv4a1MOczfkkmD;jIMrsVnw$(1Xkf00Alzvy{FL{h9ufvigNflI8;9T0wUQWc@d0+;HzT;BZwMSPq`Lv;<7mmOM>%OwO)a_)#P{| zeuHr&<>BFMI65DMx*ZQb!9xe0RaU2y`!JgH`$pyX+ghBfN^0zm_b<)RH93&4^iM8}pS1Vq}2Ad^}-T0`ByoJ_(&WB@iz z0JWJ(JZc@|t~1HSAz5}ZA{<+f7rlyo+jWfSu;O-Hu4iggGUR4WX)uK(743h`wW=9j zA6k+ez02H`7FIiX3O=W5p3%Z78pu*;G*_*#IhADgDXo^C{Qbkp$JcL9-km*vb3hl4 zkwOXTX=^kXMq=XtJ`manr0`hm$E2@|^i-x$*$E@f9fh!Q_N;2gWI)I1YGy?a+!wM1}FtVJo=Nk6aZ3T4bkqw;$-FFIm#udJ*F z>c5Yp#~~81@`uq~IZ|nMbx$;ilDk5(KI)aU#>0*&$l=+?)Dt`S zluqM9=3VTMz|rkpv`&w-r~HtO469kCSW!J8&6_-<{2U``h9`F<1C~Fw;$)f%%yS&LbVGMR^SEOA>^`xql=k8xHnC`! zWoofxHvf7ZB{{N-VHEbpG4Gl2Ys*U@oLdR>)dAjZB3oN9sBHgZ(1+g9qRRF|xwxy9 zY%2Ea^J4F&1abJ%;m2~6J;9JU&L{OzOKwX}n}cC;a@`r<-ie|9y!yqH*4`q<)E!Hv zv*&k*zt4=|$*Q?BsMcJEwS5_X7+lxXNssUhDLfsV73}2W^V5@+!vG=P4Swx`D_#>M zpAItR44pe=b3HqfO?NV&!dlyzS%D&JZMHgTual-3SNZtI!k_FeZ3cH?jsCM zE+4U9v@t73YuWKN9&v4rI+(iamCk{qRRDKVzlv5@+wv$r-O56ct*Pzyk#X%~>a$TH z9ZT+GcA<(4ZXXPl`P!4GyV2CuOk;Qe+;V%T!&La~ zHhBrl(wuB%9`|l+Y*e$gP(qiInK|j11qQJb&65gdPAHuZRVf8kDQoW>Rz`B;t_n?O z)0`LkO(7@t$#HQ}AYM0CwBCxHC}1 z&tzxkg~?g-G%gN>?EnOw#$g1MqkJtGO;Zcz-m&7)n2<1Ff+g>d?}Gg)5MJ6$o^ zKvE$N8ZVqc47vnuG^?;M;{3pBhlIH=lJ#wVY>H)Z5=|eMmBN9NGjTQkX$>6SQ8r9# z9UIlioIK5{&Ib(Z+;^-@x)uzvXf<%O2(&j)4Kc8n?l>`HI8_Ud5a4Ulo;=Pq{j+`q zTjZR!O02#;A ze?u;;hxealIL;h{{#|AW^hhQ>y9=gba@`;Sr%5&c7AhX!@5PX01j|?BWxkdFnorjG zU%GN^A;*8God4b1+kR4U&;N?Q%k#ev@mZe#U7r74p8uWk{BJ-wW*pyz*MAd;XB`8U zY2fEL`AgDzo|C`5PMVc_9xfc&`grwLaO!nNkr#u$3=_^cyL{B`^g83T>YW&-tCn62 zdc6U7>cs?VgBBwmyQU;mlFq6s`SV~v!L?RAqdd!t$4);`EX-N`96dn%el?&8dtoyE{?v zuuK8ap?V5D^yCwy3_TO_5{yo*-haXC6$U5!HLwxOJ2=xR(`UOV2g zBp--5EChP%=&TwOpfcn0TXU{1h^A^H8!rwGqEV3=PP{B!V1|X|3lAl8lLHG!vzx>i zESk^~)*)l(%05^EO*VSQ<~SyWN0246*OZ~Ecu+z%f_vh*+c5VCutVDN=(7x4d;wus z?*@aReSXfnAtc!|9`z^qSn|v`8LZRGm1ZEk3^E0WZ$5+3FUIkP%;Q zs@*j+RF=Y^`eT!U6%cPT?v2^qsRA9M^+?6ZL)o?Cs3McMZa=l=uy|`kqtwo%wj4;s zA~8CAB;#|hlKLeYvU~-*DmEB8yuixOqQNgVHOs18FzHFK56%jYs@Uh% z{BriJ&W96c94j0N_Db;r0{CLxKY(xS`+!siPVl0StGKg(V(Lzl3~iA>vp_$ch{$JD z0}@!08Y1=xoyZqLxO!~EFCZ*FoW6Pe;zZs_(CLfi1`af+Mg>E*lIsH*xT5u&JHJPt z#oI5kKmJ+J3|iL?13n*D_DYeXr-sw_PwzgSJb&@a^Pk?F@YG0dj?^i_B8Ox2G|Nsm zYc7l8S2Q#xZM@b)D0w&<<>-h1yZr;=$fmZ;ic1ACbuV6>wQbEPg@MXn`%U`C?PT=dSbRPSuwvOgO#;du4IK_@@4^o7se7ay=B^I^!H*Q+T|b zQT5>9J(|8#X#!76QtTW=bfubo&ka}&WI_H))txnG*Bru_-R&XvCt|zg++60pr( z+2x8HW1UjF>1HvZm5V)5bKFnTQ~@}< z5IYm)NudsajDVwW{Xu^Nkf8t&(9?VMPE)+OaeKh7h4MMWY!iYVQoS#^tRuBg#tzne zp|H!6UR|UA<-q2wl-z=()=1wjo3s}OA6`ZZh=#twbA z;O;ch44NK~4B@L}jEpV%`zP1&YWU0!%T?`mC=!n? zgsOZnc5vR_GRl%&(>mlL>j00a#%0Snba8zvx}O#!%)f`4redgNDrdpNWlf`_+^*vh zvn5)Wfv~7UNB1zdvEJ#bQlP3=cO=+^%6tQBISBn894dMwZERxU9yFCsg}1}%MbYN8 z=H+uJ3OQ_qq|vqPZi`;rGO>;&lQ=d3h-h+A zfL-DtV{pn=|cjjwO2@GE?;T)eJ=vr0_dJ-~(AybUq1xb4QJdg6V zgqD5o9}33&+Rf?Vj2W|Z0maHqHJyYk{WK7JzWa|E?FW#VwpMCcHPj%HNk8$Z39Y=qAS*6WqAWq z6T;$@3Z$7M!fJ=!<3zbRDeXJk2!wXZyp5{KB-xdZTw$uIz)z-|hl*E7CuO|CFZmP- z4@zv9m1aG&m;p@QWnZw17B-?vp!~Q48^u6*J$js!I>QY_(<2q()S_t8JQYL)5z0{@vD%D~#Ts^H=QTtnra-S@9!ra{bV(ygJP~Y17ptojE68?*8=H zwsm4Xsx381UC-Zs34jlP9U(3iXqPLc8YmpkGJ~|>S}Ia!)uWQlw&J;Q zA8g3Fv_5`7Gd4m;u?*Ab>ia!J7J9;Ng=_2>25eDx^^YS#CSr!=UiWN!a=MLH9Tc+< z6K8A2K%CT)JpOd^hFxqwPGsL!Ykh1p%8Lx-u3clmXp^wrpY`|m`mpPUulGhAZ&cC*V+OYH@^%Bacv z;3^Ijbt(h0n;)B(orYImT)7hHfM1S<6bT7eZ2hd>%fX<=#ywA-{rGHu?^!Y$=A-Vs ze|`vN_^c0T1ovsx*q*DchvQna#a40(j_ai$b$27-77}MA6Z^*!aeKYZGotAf=@J#o zSKW=A+8}#cl|>`zaO~=#P-YD( zN(Ajh_8&HV2STkn`h_X{>h<4JB8|O&U!Zo8qHaP%gzpVR<8t*lnUAJcRWYgqI{X<4 zQx#|x43}^nELLZQ|6sxkLVgWcWM>(==&PAOC)OcHC}8i+4q(u%)K}{)GR_zcN9(x zfp^6}RV%)FjJsM9*NG)n_eXN6Jql&1PZ;e(*~25ZzghdDx=@N+F+JJonr4qtNRp{j zlte{lJCV;&HVYL5EW{jF*g7uK?8JaYPOZVYjUNSZ@@XKtF$s{*ks24I!!a&)^Q<}0 z;aamE>19URo1nKd)CCBbb<3ICIXVDgK%T#W(aKt$>Ifd?Vuxv?MEJ1b%SlYq^3dJ5 z2(qj@$6~yI)FN~fZ%8X@@*l>RgM0*X-o+|!;mUEP$RdKAUu)o;!*(!A8w{ChJuCPW zvPAS0T*Q)hdn3eOdjH@9H*mQjg_lqnB*X`7Zf`<0j0kzc`f62aC8~QcxM*tq;y#jJ z+((E86*Q@yZ*8?~J6k7F?qq@V=2#Z^B~&WNokyCPHRPsPH4O+W7%@F>89iNiDG7Bv z#@iV98iQW5w;Git_yS>lIv@7W!RvlLQA_af%&Fw_?pfoW>(9Mb*hOy>kltE^&!3G9 z-2{T&!ojtRFMcoRr`RJ-Tb|Tqy3QO5)TH_N!HarxDmC^3r!C9r+Ubg2?O>}0(sbG# zGf@y)$Xk)A(&UTu-PnQ<*{l3;dS63!jmuPjj(v_|ZbFbCa_DoUEOr|5(siI~Q^L1M zcQL|dK+baO2kfa8-i?qL6uz^W16)^5gQvB(rBK;iI?-ksc)ZgQflkjg_%dfqHY={V zcNYm{VNTXKqXzzuQh9b@q=Ft?5t6R@9tyF0D>r&!fIJavT^6{`9iiyQ_rH#ZZ7TFq zH{PQi-&30}Jk~$^hAtoodI5;13rI!ht{}8-u3Hc&lYuv*QNS?GrJYgC=a#6&k9?{r zr7M;7-y^?u(=Y1JI=0up%cm&*7s>-BXw5a-D3AZOv%mjv&x`-Hv;Sac9slb#KI`~j z>-b;m_+M4=zou#(9Cee4(r#r;EVWYpSN7#6h~f~$_EPU65j2BhsIeDC`NHkGAQBfD z1+b$OAqHxaSSaZyO(fv0c&*B$R_e_QNlOC)*xj{SYTQF1yzs-ZEjm z7GP_BisZlO%C%w}Rr24Xorj+Mw|nq#Z!Q1b#%C@6t>wS9{I{C?_jQCfU*b9ncHrpt z76;==24d^hu|Si5%0h6xB+)lmk65v|ZTDuv^<#1>7G5rr{5Otzq-0I}YbBaKp^HQ; zkXg=dJmM`U?Nh~)scBiTs0^Hk*diE9t~;Gxe4)I8)C7E$sf9!Xa9j&T!aQzAkt!x{ zTTsI}A6^;J)zAvjQcT+j(&9kEMlj@C+K4KHth$OfB+kPa@)Ck)^k_J51mKA0X2DM8EpJ>T2>&lDy1Z$wYYnc<6ZA;&eGw<+wt=^7i6W@N$f2K z`ciqV3=Sq)15J^e6>W>;KVw2(J?g*vl*@lg@;mV5KlR@_{{O9f*7Dz4{#(m`OUD1V zi(`S{hhg-;QM2irL4o+EgSi#~D2?A=BS=3M`3}9vRV&ls_^cpCzk5QLT>>%EyV#Aw zQ73T+jM0l@33IbqkOahC7x5w--8$(c+Sl>7-xA^bXkTn6((AFFSCmCCvB9jm<1^qx zwbSO}dKNlvOxJUl~5mJe7iULABt#oL?Xqa1VSwmhl%fXE zFjtuKSXshx!0B98@E{<`aUw1Y>O&H_dV-5-z>0}}WUu47F1Tfv zT{*zm`{}fM21iO7?)?OQGhLD*?RQ*inB=NC@uWN4l_?VtU&PX~TgY|>eZTUALu{=a@Fy)71US5&GHeu>| zr17p^V%x_EGIre(plOd<_)2XJn-ZUkY^>u-D7w3l6NUlwYBpo;jH*TxuWO<|9YQt5 z5TWfv5CMv_vp5&z1Tw%z@|z1*I5}ZeG!!yX;9Mbw+>#7@6s(hG*8MYB8;W8k-h1`> z$@3S_NfdzY*vQH(aH5Y$!7^;u9ua(>FF*K#j3ex|Wd=1q4|e|F1FyER2-3H9BdnpUdk%F3a$u4x4ku8S8cPUOQ0*JS=6j(k)5LDDths#tluHgA7N^-j~)AQw@>%<^+BRVxa=Oz(=4QM=64pMKGyTF=Fm=b}Vj zk4h^XFq;wvZ;JpJR0eU!E1S)QQ>zo3HGcwM`sn!&o)X@-XSvrs1FG=<+1uOk{l9m2 z4%YtPxAIw^|E$k{*5^O9&wt#S81dY3KZzLn_~Z><FOzwwaz%J;u^AMWfv2=0IFt@r<1 z`K^UcU<%?NFNiED!i1-&H#kJgz?9eX~;`6O6CAoC%@PW zwa&qA{ZCuinMAl}BKmV;pg=D*`{PYaHS6pUki(tac%5r3#34t)hQ3mC+7!mIL6s?& zYNDfAK-6+8Q@G?k8af4ULnP$+i9$tfToGe|-#kKCVDqYiXg1kMc0Qk;IxEj)j`4fh z^)?KJLT%Vs#Ryg#$dyDh*p;s_&jZfqtN0~tZV@(hwD~3 zi2x_3=y1N-ENaOGTrO+KLukvuc57m@R>yJ*;E-y|cX4|Ht*t~e%N8(;;wEw6ML^(i zd6QAU!J-2vy4k{uw$Z@C2obEPSXZ?j8CrSt7UHl<>&v$*_n_T_O*dxOCj$fPBPF>) z;#7dmDtN4j0Rb25#-?Si>(fO74iMuET)eb$gjPXi6(mU5ghhcG*|bZ^b%??N`gn+C zN)Q8UaRgRwx^|=FuENuBx?41ENHnbQLJudAEJ$y3aY+CA`uXd_b|=ScNOWaMNqLhm7P6!XVsA4mTanrJ2YX6`p{bD0x}V^r&xVDk zK*OB2&w0WFOT0cy<111(+2IldXu6c_ceoDV#SzE`bPLPfaWlBY&p}awH90 z84Dkxs21}O3mxilkUxPf)XOWr7Wi))KL5&;k7id;673o0f#X_51y51uJw?QH8XA9> zD?+?g6ZP=$`^g}KypoudRXs_^>OlqkOUsT%xx(9agNkY<6ADyx%8Ip=8>@HeY_WO~ z^^t2wmUN!RSH>VrdoY;2q2F)6OtZwio2wrN3?9gjwY=vtEg?f=%UnA;NieT&6oW>C z&A+W=Zyyc*>fbG^D5y_^gZpbhtw`WaC8;);K)#jm2$o76-Ld=+-LPF~c=HQ&MiVhy#k?E5h@PY#K3FgxgZ>=?gTrQ9?(JRx&p3EDb38FZecD@+#3_D)pTe_%< z>2IC+rJKGv zpGcKxGIttbXhAAt$JA~+BZYU={VY@%HM;N!);gze0iiZgX@Pfi^aZM_QIHJR!CU+u z#KQSQ=885OZ&7yW;v2*+UXc!Qi%Gs+*jFyQ+~N9MGMJ=h`Zm~lk2Lky!J|8gFaT0j zX(=qOt16$)hLEVh#Wv7Kpx&g5-`MB=Q2_esa1NUWMMDxcx@fHDgkn8YFl1U&n_s0} z;|UjQp0BDE9}iKGsd3mRYT3%VBXOqey~zCtN*hVP8NWroK8gJ|{FI#kV(0`4VRF4T z%FloIcXoDn{PW)jkJk79Z{@Q-|6QN|uFrp$Isat`xe#M!GQLlt3ft$?>AmR7;dovW z_0#Ra^MSq2Exf|yjc+;>)<=`yPktJq{>y&9o(=p*phV&`9!m=S%I#?~$~5Eo>)!t= zsT`$Qisfc^dr04SWOG!q4KDnk*}_ zm}01!C4tXs6!r2y^dm(y+v%uc)+kAFlm;&A1nytukeOtjT4r*OG+PCw$hsVqq{q!8 zwJh+4Ssp6*t)%R{Ub|kuSB4Y8KZ1KjYx1?zD^5bZm`jNbwdMd@Kw|LVc0}4W<~ePS zHkzbed^QujbwRmeOU-W(w#&A8xrrufqaLFHrGJriXVe7hP#8_OE^E0OrE^6VE1N5_ zWa(USMGNPOEaG6umykp>R-lIETk~47ZPsVs%35mBgqF5Dyp&%Zp?%rFP;MV}Isq}zA{Zy=-AK>LfLJ&NcU|A^mUarC3zDhbW4Dkm%81k* z{L)pjxHqCl-s?z3oa3`7Zdjak-x<-yoA=^a88=tG0=vTCZErLJl5IA=M#!9s%fNcUzdm z_xWUM*=U0=Lki8K&_TM8DZ3{#5Ww?AzxOjr!rOcO2CsTpl{ zQCK@9RuKZr!-%2+U)6x)F|5~=ETEXG)_XetL`Pb`*Xjk7T(--lwO6Vnnq0QERT^5R zP7$H8_(hhp-C{9Sx{n%x#dxrKy=ojUvY%ILv#45WldFt#4NBsve4bq><*k|n6Xpo+ zRW99R%K;4MX_wU<77I)2)nEBO_kQ>xIZU>9`Ie{@rkCUS-opb&1NFm4jgIBc#t`%c zoJp)I>#Ex&r6vT|t5P`Wui0!8Ayx@IIidg~98}S!UU5Q@a-*hGZqZ2s26dXvh!*GZ za$QtvH%uNNv6h`4Z0RYytX#M`MmSf=)$r#C_)V!k*rF)rhX|iqgb_#~aX5A%Ts9{H zgriN0&YECJ-Vh~i6OqEfL^-wsr5Pv) z4}-?2GO?YEd2ukd{rZrWKua!mHV#%DJR()Yh7Bq4B%#B|jt@#&_9}`|h}Dg*F&5Rr zsm*#=Ilt`y;MiC2E~nDXHji|#gMuYhN&Aw_l{h%+*F^x@){TH_M?u6qH{i1Im4)c^va{hhPvNk&h9ve2WL@(YfGCLib<+If za9Y1@X<1=SQ$<~BW5e2v#AVZp#{JeTzLW9AmlQ+K*4tfNrTD5(QkH6aX`ooC1SmEN z;c%CQxn!OGLM^u4;YDcPfv0KTX$rFp&w=JM^&HkS`+|J)FS70cmpL4o;oOt-sgSK) zQ0gN4oc2f4*m2rk01(dUQOU1M^(d~MB_-*i)I!at(7Tjo8wDKN(duG09$bVPsD*+)_Hjs~ z$sh{>`9A#!X*vVT#4PIkeD`(?gZy$P%bI)#xy zo&S;XFxZk>xP+*=JU7vY;de_$z1NL;-Tg3 z?uDAAc={glB|cBPxRvoebe8>`dXjU6j};wGgQrzoo-3~|e396dj>wTWG{J*}HJi)$ zr`y{8wJ<&4CMN3Akc1kyW%D?wr16F*K=HPYp^ezkqwNl0Y|PLWLwHq$Wi7JM82`@136c03 zBvNw6%TsXBPJ5Y+xiZYbn>GRSLJJ&qA*eh&>|R_b&bZ&;+yO`sNjUj* zo}p(o`BULLtlNjB;o^&}WW1j7CK)WM3aZ4z4VJsVtfwUrhglr8XOlNWylQBsEUH@A zm~~-_)+AA7gE>UiLSqG>Ozd&jxr-Nxj)vq3LpPp6a{c)ee@gEEaDT9Cg@7)<|MOt? z(Vidwarfb){q_By+xV>S|E%x-tndFUlm9caI7Tn`+-DxSMFAjL8qk8bZ?bvKP}3x8 za=e~EUU3;A(#ZyxbewsHLm~t&J1h`HTJU&2aq%Db_pmaljxn{76`W5}eI?vkPF!V( zOb5TnQ?bZlTE;OMoaRdBQz|TBD$sV2rIla+ZlSCr6IRGG1T1oh3-Mps7h`{zc88SN zn=)*nc-1i{F(&60e{X5mNj{DzpT-n2B1qGvnh<3nSil!s)|$^uZ{3JY6c-Q2-HXD( z3*Fg?pj-`2Sq;3M0QM2~Ow*5dpp8n762%PyG-?<Cw%|Mw_v=?9=(QR#gb2)!?u3LgeX&&XI)}m7ogWfLsKSWrtZtk8H76oB zp&ejeTsUwHRhwQv!uLVPm?aWJk2qd|$q-W+s#wMnz}_h_BYUmU#9)=^PHbJ4jc2Zc zBgPZMd|cWE$7N9yY>K(m9I%i-HSVTy%CROn-OscZ$+hNyT;1^snFT9|n+f1K-@-EU zG5d1qVXJ7&5!TQQHm=)z$)Ij4V77OzZ=zgv7CDK$j%Zgh#g>^?+On4Pd(=w5*EWG@ z<~gtuJFW)CVyTi#r&`Gj)3I5=F$!2;m90O0Om?|bh}1;R7ZK8h<88YIEx1HMV7wDY z1T1chs&WdGpNuV z>n_81-Xt2c<6pjXG}|<#%QnxdHD0WYLnTws=5?0W8`v6_+URSnLaVPKcEpxiJ?!So zCYI*ml}27M(KW|iWLA6qU-G>2553t#O~Hv2ZLX9NMXI_&GEjoKAKtur`RqlbS?3fC zQsBHBBQ|Qm!H$yEyJ42i<{>2$E<>+vg3mE|#Oxne^+)XnHs;ml1mxX&^Y+QxcW)Y+ zscTM-*dckWhgXrj_9m~;9X6%-&IVU+zohkaUFr%j7X6m|2tm`6-+l}AQxQ(RIAI}% ziUhj{0f%pxNLwGZfJ47aC>ou5PHxcnlH*i#7T&FW!?ze?Dre7c0Lv~CS3_{n9&CskDghE3gy4a@%&3b7G3XYy+?zq3MS zv>;pk^A}Iw{f+X`568HjXgX*xhY+0_<7g(6ivhW*V&F?POt|G#wr2Mozt_-a3x{+_ zN4^9c?XbLs8laEj+-Kx?T*D>DqV2NLY}34?5nPUigv#Ocf-CK+fl|HY31NDZjCO{G zX$7^M*MOVgn+;48`EKZiIR2;LBw=^@?0ZisTm~LVE1?6_>Ws<*j7OS}THL9&0bSsX1FopMW;i zdv&#dF`kS;Fe3-oKbUytcx?nNe@4|udRLqi zKAVhs!*M3fe&Q7ykS9<1a6Ees!P}oaO|7d#3n@X)6m{oc9ytsntYO4F!=20 zJtV()_Dnr{<~@6U5640fL`fun&&a*t6#O%K-7|C;L4!~`d7>aIK;UPRJa3yC|4`(! z{?cmr6-l0ec8g(Z)S99VA`qT_a@quN|1eemTULGAl)s-TP*1Tn)#fZq0HlJ5DE+sA z@jtT8b5-X#Z(f!CA6?c|`GHxK@&uzipo>ewF-?BJHo=u*JRhQ)C6)hlKJ1_4yP;q? zbl)5-DC@zj3!W@pG*2+>erS5AC~|-5j_1g-B*=o$`UE=--=3R-3<#D0QvIXg<#Tvx zI-NYZxUe>~9$E`C(P^xaj223`?PcIhgYZr5VLNLB?|ssIp$MVrpwR7~W0+4>Cqz%@ z4MM3Iqi6mPS!d?w*(hm1|L`Z_>rv%9@I)C7vMxG5O~6G~QPsTNZ70u&R-^9c;b<{3 zV~vdQ52W4ykW%HaRR9J1x~4uieuCQ!`9h7V2hc-nuZ_i@G!X=RRg~5~IX!Q!QBC7% zQagFN0C%LZ9p}+-JRCtBvEkeRelr1b^;JPY*bb8Fjc$bT+!&Cw!}E9WB-VAQUh*@P zG4+5(vyVwWQ40}B^nidZ@WjwPdCS1WPIi7$;N3zcN<;Utlsk zwu|x+GK3f=h-bHEkrSw{k{J8ff?1!rFz~>VM-MgMquSxXbMnxDyR`zI;mGf|B{iNnYS^LU)bNF# z@3T)JyU@lVFs?1$W3wEDcd*SR^c2PKBl#3XT#%_ihSE8nA?Fb?Cnk-N3@Uk1SMW0- z%M(kTfz&%-!Cf(n(IrN|iAlt7sRjK3Tx z%)ut4CeG!~m7X{bCy-@1UKr?A9Iw(C(uvt|;vpUJ^zeF#6+igSA5phOiB)&}MJDIt z=pcPrxQ_@PYzSPtc#MaPi^e|)^)Ar$k5kdE7H=lvvBX<4f8Txo2*kHwQycg6(AY zgWZ+E5Fm8m2t5%jPN`TmNAer+JkiOThjiy%Cpim_+0|ME54;0+#)8slSH}efnOI98 zRSeuJSZwuDYn?+etEqlS7Ba?2$TwpWuu!^HI*7e443`%o>%OU+Pe>&Gm`R_Iu2P&w zAd|uE53SsiXyuKG&z~6w**GATauS|J?70Mik}z)djM%aC=|E^ zD@W(JgQB_Ornnhz8m_|1nh~qnIFOU|+KnX*@2MU(eST*=Ze-bNwnzCOjjcU5#9)^A zA8}t)drheaQ_IJOK|l{+v6J~Oz|H|!7V|uS3;ciiUPHF+!6db`^j681N60AJFuV)IEvr(_5ujA2K#}(6}SPYw;4o9`ZYI$?hS1QjA(&Dq(q+$mwf`{ zE&Lw!|1jG^w;qsSRDaKHL9D}eqAj;EcpX}K{bv3K6<&WG&u<`fC-Nh{Rk;YWW(u%ue*PEHa;%w1RL&nIEv9Q?|XqPV!6V@U=_@F(=~E< zh?@kDua|5 z$K1<~kTLC>Xsf!)0wYA@8Vs?OTMi4~H??N}Y{c&BF2XV)5bt1wSBwLWov3saC46AB znNKDZ&APGMbbg|u@$;-Z&}4*2o4n!nUma?Bi0@x zmg>4v&y?=tBCTr_O^Sk@7Gg=;5WO>@$MN}5Y*0_i-I3iDI8UlWVToir&B6K!-x{$c z9TQN<6UluY_=h@m$9OiPQ~<7 zLaGogksBTTDKc-~c7bTUUDi;Q+cG>!6#;!Zhu~NZo&kr%bi>qsfWnzhmJ&rUkhDwi zjGYveAbMq1BrW#hNxx3z!3POr*RD7+dad0-@|(eazwv=in~B|$ODeW?l5kExO0HTM zVpEJE&Ic&{7qu4DbIpH)PH7}S4~B583f@b-FUey!S##HU5T2+BwcJ<-A(rDpCy4lt zl7YX`W0*JX;@_<3?ObVtlX1U0*YhpjQ_?YI)DfrP9#0h7y-Oll_k{i~PVaE27S0QEV^zOV!#7 zo;(Pi97xFf64>MDFCcvIWcMI=wD*9n2jps*=$~u)D5*?0v|}plD@3pE{0Hnar}&6} z-{U_X^B?k)lUH;j|LyD7$5?cSz51SLs}5<8I!-zmwAj zC{mkB?uXQ07TkMSF6iWl4A7JqOiVBR2GuwzI2$NdeT`JEtacSiFhH}?TfyET<0@(T zrdBZ@V7=+D)uvjDT+7001QQU5_5MRg%<^VrSq!jTVQIYWwXtf^@%tpHpsfqVt4_e{ zKIWRXjMJ86a8jg9b^q{yp2A_IGn`cM{<08@4;cPL@%5|h|ERiO&-`DZ{~bJfwDZu{ z|8^ceTI+we@mcGCYyEGn|1BT?T^x9c_u1$Ec+x(fPNRotUiD0?IG{qry0BRhng4?xixp_(@=5+{Q42$+Vw%iOCuvBa z+y^T8YqF~t7Q&Hi@X)D(+UA0UPjgRzEtnACnA8$}ho{E0LVUH5{1BD&j#0m z-%=f~XaeYc%{KPR+5pJU)d&?pFIZhK{WdPI;Qy^=S$o3S^nA$?v*qs`G3%lH&i_h zbWJxCD0yLt(B!wuj<-|2UGqnJ*A7ZSR4uPmJ~tANC)8*peVN1n@ z>n{}&jkb52xpRDC04F3unx_Vu+5T{P1Pk|K7BKni&)0;w*erHs>3#wID_wUo1rsHgeBIK;S$;)U^vF}!N)b{uVt zYj(gQSA`<|%AE1F$Gmu;f1lC4-YC@=8X=S?l1GUAuWUE|<^syru-MC@!1`8i7$_3F3C|%246iMnfUz;KHVC_=61(Luh5>f zxEUDn#kIdn)`LhaO*_I^CTw9fGMObn0qrC#Y7r3PVmGSxUqp2w6wNs3aPOdm@vL%obU&Ap23vuSzII`++4F`~n{mNir$~|1ekNQ$siS zdUUf$WuNDA2$?*CXhcR7Hux2gH5_BzU2hQU)Zr>y!=knXY$Uq}EmuWt89Sd()u(Cl z-8X*t@#RlX-o9wU4<+U-M%f{(m}+TO{rbPN>}T9^|1ZM8v#TCNDa%L(3D#`=Chfu; zR1i1={H$H5-MXa3D)TBqmNw*WxEkt-+B=wS(v|;p&=eFkn=BYS>0UEO=)oZRr0_rS|s>^C6^d^90Ihe|=n0EbVw_t&6!PM<;oBz|cSf zYy#F`W`%_W-WNoTsvsGFfjtGt^6)^AMH1riYIJz)li{(QUBD8ORq49Gq(28o22ZlP zi#+()zlgZK8%*VZ=O0UBK6FcT{UsOdJH2i!T0{O{%nmcgp&uOa6-cc*%6UvDtWQlQCfD zhTA>~luB*Pm(2;|F~#YcOtbn}l(V}@yq1TsyAtx`|` zYP2UCC&@qU%lZ=u(!f9p?yo(ILc&K`av8E0;Qkd+X8S-n_E5ZIP6w_>{dg}R-~xzc zlT)d$HdpT)kK-(0b{auvZ*r_EJ9vZrs@0vF8N7J6_V=#AeFk&|^Q}G{;evV-X!{H7 z%G2f6=X*>*S%%EN50$UU78hC0OyGC`m13}XA9K;I1dWl~7?1%oxq~!4fbcR994*WD z_ZkcohJ86QTO)trg#G>9ugY_7HbIqR-qCAPDY625ZBpIBsjBLPsa~Bqm~a3KTT$XG(R7n zT4yvjG{1DwNm@0S{56malEW%}hIjE2_Tm;myb9rk0V5DM#vbWbThU2g%-f30Nc0T32l zMgc6_hTFJko<;D>*`(`ZS(m&5S21%^^*7J*U2$M^7O&<5KF!Q{X zY|hVzxmm{nU@?OW&oXSgYRNC?xTR*zz84KyZ3@VRkzrLzgc?1O-H?*84*TQS!s{~z zYBCOCI!hHgj5TZUPC&v~+kwYxNcfsam=%Qw?~KeqeEoISvk(hCc9E$Wj$SeT707=z zw2N^rUgIFnvO|z!$b_pLlq#UQ4b)sqW#-$+-(mB=G>su31?P$%$x&Zy6U$ocmg=49 zmq#0cpSw0@ma+=mD*Z#F96&b2?#LI*} z;8d^D5gb{;-Zg=QHS;erx-Wpn?22@y#YA&rSAg>-yF%0!Iqx(U>_$haJBNN{sd{-; zPH7fh*itkSq&P~*t*w7E3Kp&+=;e=HhH54TdM7xjM@sz~p1CsT*HfGVQZF6b69)i^v@oESAC1zhWAIA9g;6a0cwKUKw zbkh9ea9V;>92=^2lPFEb7hlrT;ViFv%b`k^6-o%|IO4|Fmi3!+SH0ZMVXj0}DN%@Z zx#-F|Rv|I^z=6hJk0g-`Ao1%TMVOU$n<2ksw~=5M-LKngcf)VHsQWfsMFkzc7OIA4 znct_yIT*7-4(%`IDTMS2FG<7Gw4aBgh8@yxU9txD+g%V2PdYBL&uM=&jor!Ki>z>X z55;H@^i{1Rp8LEc?25rZg#DcvX}|8qge~K1+1E zO_g|~CWC`h2hG)| zLua+=!1y4F7jeNg$+t8MV74nW+H6BwjlMXcC*Vo3^5S@_Ya^n%^7Q-NW}hd+^e3Z{ zQeHI4FCg+tMMo$_kq+G59cAfaim5TtnQ?WB+x%@z^09r`unqA=m=Y10H)f-#*}-dV z78-#NcDRhYL*m>Gj#%NFc73lzeVK*lM#ia^M}`I(T4GFsUNHq4Z%2UG8=)?ODnK;v zcgKzBlm%GD&CX{^w!db(N-F$ixwdB+1_iQ>OGjAL(Spb{{v|`-HO{I`MrklJOp(A$#>#AMiBepeHjmAMjA2`PlvgnA z4hEFQj&2+Q@pZ~UwSe_nNi^7`)m8hwHV{Fn`Ism13s2qWDT4L&k^Y#1?ckR%1GReU z6cd@{(94piN;;>rARV^a{^2X0)5&azM*on+h*E6{f|<3i*UrZIVg~7s^Sn_u7zi#e z2wOB*s5J+dn2BP{tUKCBCi+4V#)r|4J!)Jo_*|Xjn9l?N-7_pmQG-~Z1YPJ7vz?G3 ze?Cdiv(F96hH`b!P*s;iPCTUSC}wKH^LE=k%Fy#rS2#lBgsx!>F06*OV)z)^@DZ3e zWj>m|KX~wglt@~(r)rAMmEJX)wxE&ee0Bn}bL%e`gQMivlfUfj9$Z{}zSnYsgZYHF zKOiK;#)cnD6x@r{i|sJP)nT%|i#xIeq_4*OYK|R<0t!Q-9GK83=+7m-EkO#7s<~wqX%7XzcI^=t!ZAHxhSK zO~Y#0&a*(S*XbQHfr8a9=-zNV$i`v^!vzRmIa>&o5@rxW;6Ic9eamfYqJ<|Fe0nH1oGyG7tdZkd6oFH?(=2IC?KX+{~5HswC%?dR;@*sCPTev>Cs*- zxBwg46SaYcm}<(77G?N^t<$TLbFp}tL3Kf3d5pagj(-9hOQOv_2qP4aBook3zGNKn$m249{+T&A>_ zndxCt!9u@UPgP*3IOXQ40G>20pym>=bed zoFqSuAVY5U(mcYzcy8Sd>ll^@-)whg+1W5xzjQP|7O&GB=kti1_Fz92RG$|Fe$*ij zP3u*m2v3!u%7zc#+`AH}NJM0Ne#Cwh8)D(fgNXb}@HP>oOQZ602M8JaKN2oInjzrG z8q>Y{JQ1=Z6fhVOOBOe-#(Wcsa8QzLdNW6&S&&YEtrR6RjBQspL2{kv#Sx>Nqx}sk zo<+n(^GcHEl*qvaxIHlm8Q`FTT-3L$6O$eA3&P9rUTh}el+fh>zO*uNh)5^~kcpSP zV-P;^?d#{S57lz`SuH`Q5D4*$8pFwymC;Ldbk*UFv~a~Vk>==gWxp*sIW=H5NjbP{ z081L{Y{-WwYzV7Bd>1qGf=DAJzQDZ+w*{1kz=ax;z9J&uO>y6Jg@qJ1tu(s}He4`Vrc2(Y-T|-K?$Bjg+YRh1;VQLZ@ zo*?B{M3X^f_oE)p_CcctO=@GaI(1e@(vnPLiMkaD^=`{AmQgzzHLhkEX+|y2dIu5= zm+6cl1o!!0teJ}sx&ZFJ^b^gcO_{h}ek%V=iR4gcET|pW=t&+#G+PU<=#7Hnd zTn1pB)E3thhQI{$A~{$DO66-YsUSLnT=Eb&1~U{@+8Bq`ol z^ydj%ZeNa1C#XtjD>9sOeg|PtTrv>jc0&6t7^&owK{lPA)7I+m<1aqXXWh3QEu67t zArt~pAAbp1jg(EQx{-jfBZKcEguGRK@Ks9IhN!>-Y7=YtSfkWYY7|}FBA^~gHjGV# zG^(L`)G{b-P@}>e>!^iSlDw*INlbR6jL&#Zm87G+i`1{cW!cGlhlgm9Y23pBgNZ+% zOp@O4?4Gz=hNBA@u-43NZ$O)4nw(f$98EB~bOp@z4kJYTFrR6zixSk{g~J|0mvSnd z8ix#`qEktUj2fS}KmK?6=IxWW@7^>xR@)u0IW_{4dXW%|Mp;yB&oT&{OjiZIOf#4q zg*6WkyZxUR!&#QjFRz-G!Q2G#Gv;XSR2`emh6C>+nXQJ@Nf|?=7WQ;DnWHI<6c(JR zc6!oSHe&OWMI&)g!O$TYOk=r`JTg{7v^SG`RahKeW;wm))rhggJzml7VX}V|DZ<;b zMYNL}YmRQidQ)BcR2dXlWn6(O>c$$`BDBoKVTNNtLz1J58}bm^G66z?^&z<0?m@G- zJ%akJdb!E4*6S4Ao7Q*~U@*(jY(1SpiY)K~VGuhFT~{F$A&FQ$LKIeMeCcMLnVQ3Pt&0gE|SbHfvb1jEmmx)hBhY>MYnrxB;)K8a#D29HG+yc z$<_sF{bfvTx+0dOam6+sSt6-E9oZPf*b(2@On3@jK&8`9`}Zk+2Lrhen0#G zUW3Nd1|!s*&L$()-l7MtBtz90KU0JzTfq~@VjfMA5u+5)vYzZIKJ>auyv+MbqhLV0 zVW7DrM_~!NV0A^9gdeV!GM-78#i!j@5ttUkxXKWS_x(Whkao!!8Y>ka|d@M!7@DJ+xjl0wD~0aCOHmb&BfI zbH*|$$ND@2QWzxRtKhzN_7QgtbwZF z{ZB%k{GqEz0IQ*Y>R;*;a6HtmKb^q9y~xq8jUw|MX}h!03zQb^yac2Ln))s6&;-j_ z+)k`r)IK}1#ftjHY84eZa^^nf#7)8!0L(x$zgQ;?`klnO7Lwvn*d_?=T1krw;#LSh zLUD_HJcnv~9%tzfg7dJsTEs&H<^uUx*q7IOWdOYTKO+(u=NI%ESalF;x<(g0|Uv%}5huM1#txXL8+^1IFMz8ahT%0Y^tym_XmZ z56uj+Q{yA?M6GCFj;#-Fhic4`1^|3h>3biu6xI|g`koHQT{BeVDv5yqcDbSd_y!TfeU9X{B>YG;Cv{xgO6Mo1OX`QR6REoDr zHk9JtDOJ*Gf=f3_)x1`jMX!IJ^*>T{qC8!U^+*ODq7x8#EXxU9+~>Z!s&CYaSzD#Y z+OVW8ar4RD`r1hP&9!!Vtxtvi=Ol~%bh>IA75d-7!TuxP|L4)p?ppu5jn7*DTkC&o z{jW;@tD$!JO3(fK;K&~r%iyKGQV_m|NS6A}r5_s@WVz&oRE1Aj_hZ@yVz|4F7$&(a zs0O^>?ilzW6{f>MS{UdeB2pINEMhA2FqRNp`6l{t>EB8Od))7YFjf-ZW-_d zqyF@OR%mhdM?Kgv*fOLO3mh}6AYCAtnS?k6=wVX|!}kQ?Ln$-b$p!aX+>AtaH1Bj` zO;b`4-+V6wZT8w2RSPF1uCK-Wa7b9O@!c$KH8jeyP)%VS_94r?HOi(cG6@?r%4nJ5 zJX_TShT!HQtnt^9gu+&J31VVGS9F#KZK4;Q24Ux-MH_tE=w%H-y1HgF)Gz3Po+{wL zqvuS3|Li%(AP|1tsvdPVl}r=@*^7f@%G`?o?J0Z{K9|m_fq*q@l9cvsqVODo&E;t=6;A zE7f4X4-a4F+VSxleejWBP-lFE-j4Pc_i|)qoU3DDgJK^~HW%|U%V@{M#bB&&>rO(jVtrvSPL?_Mvm3=X> z{HNXF?ARUbVpNaLkv@*n+G=yc{h*PDxyl6q38<5;4L~X9%@Br>&ad@CI@?#^dy0B%RBEjb>%SEh1+y-|SfY zMn6ujbkp{jHurONcr5I+H>+9<#gzy-(}2@rAz(&0V$w@n$KT3i*ee1J%=a<-a_Q5i zB_L^DH+@6ZeK^;l=@fxahvPv*ff0`5s=!@aA{!56s4YTjIN$E%nVOe_5H&WhTruB+ z+_DQ_266D35?#_d*v4Vi6{x0ak!P-+zP$4`n5IJ;60Ak=HGL&*1qcG>QJ3vnYHOww zRs09TYV@>JAO>j>NQD#68-fWOlbb*p{hqdT_yL+(-b)*;t$D3kAfiR%>KK^^(ay>H zNIcD9uZ>eS@AaCYBjT5t%g>~=3fIRR(v^}oEJ|aR>dx4+P{b4M++Ep4Z;$2h_b>s;grlE zdZ%_Y3ATG_QCQ{e&h*HdsMCD~1X)bHvs)J)5S`Tb{48`>DAaT`Cym zcO(i!<+?=iZqjQRYcW={|D&!JlWdFkSmU1a*m@;#)0chQX$0hQQB{jbRd_#M>40oZ zlhH!Sy-Ep&%#Y^oNx{bB(bkQbTIOYR$GaxnkcjNanyp6mdvu5VF0+V2n+`!Uwav~1 z8%E7FB`O?AcRzLvF-wWd#4s080t-i??G_!SdJ7#@=fQJZ$>mORe-lS}^M0#{KRoQO zh!TOG`D`-k4ab>OHN*FeKwTb9um>uixG>j+yf!`lq~~3q3+Ibkp&EuR5a{5?7jNFZ zdfVu>B#FBzkA|QN^}IqoTL`G%Wm4)6GGR|VsS`tj?q&5gp%`s)vV;tVkaim^%Ai>0 zGQ5{69Vj;V(| zR{S6}0&g0c#}cdV_=|Kk=I9{Z3gQDZStIq^MFAOC6ErJ;yS+e{!?9Tmioy`HhMY2V z<+b?k`yXFCdG_s-r>|Z#7>jZ*_GN7g{5^10%(@V@L1=bXOLS<8P=%chLKq5atFUMg zFd(e>Uaqt@+oUoU848?Yu>rS9tv37K11n&DsAn@!vk2XW0dYQ&z+&A4LwPo^{R(&1 zljzPWVkSd=557;pU`8YexU?N1XM*=<+unQ%szdJV4>r%F-3gDPZm zGP*3zG#$496;YkO_$1Utb(W3LHq($oMJs|*vGK(&-c{^NPr7Mr4E)|p;>&x>lC3?7 zTGR9+PIWcc{AnR7w|s0E1hVMxnd}>Om{~^@^Q=1sRvSL$NS7Z>QcKG~sF#F{qU~W( zPpg-9G={--MstOA#8K4FnlPsb$CYSiqfLpuHA)`qE)aujTm`C4Vzx!MZ~Ef_HZpJZ zE!dZt@rxO27zqNKO?0hw70kkN|GvmG!16%vFz)r2r}O;Mc1nzyqse8##1DoGRD;YV{CXSlFOZkETwTGPSgq?6h3EQR{q@&VwC z>lHwQ2Z}6Mm81|I=FZmU_7;8ihR&WPs=4hNhDY)`!y4EAua%tv%36Gctbq`ZZl*VO zSYN-+P`qN~EeLEfAXI+45sxv!OquZPG1&z3d zT#SU7_O490u@+k$`rR>H&?WxUI8t-k;>DANnS5#U0pObE*=$G)qT_T%Wap2%zOeVl z`BcS!xt8Of{#4xm+kd!!;OBqXIe4`8|GSOP+W&9u|F`!4TkZZ|c{G)h5+-;^?FcID zroR>tm%s1tbP5p{+qdS3^E@h~)Kdf$ntrMU3OW`X4f9cV?qbSuM8YV?%x+Yq1L`_L z_e1+@V4MQYOw}Hq4%H$wSBf7~6({5QaJbOZb;wSus6bP1soVCvj{ z+u8D2a_c{uv{Xfu;WMsF686f(|L#3s7ICvUrFXnu}l1oZrMH0)#3zHa&E zvc)jR9$u%#L7E&SR@{g{4+40H`A~}b(x7at+;Zl?H(QKoJn@N!)+oxClK9;*K$@QG zN7^W8*^meW$r01#-P4TX>t{1K{T&P%#`nCSl+#eCxM;bJQT3ECtSU5`{?Qu9l>ao{ ztcT3@lGtnqJ_qO%i1(7q$3-^g2&w;?R&-pCqFM@S!1K}Db zq2HASqRtlv;>M=Oo<$g~(9`G6D?PQggge@fp*8VMtFmu*iZVQfz7RU#aIN{~w`U)d zqvDMus)()jv0$P%lYAo9T45AXCT!WYtP|`Lg77#G?Mv{JDjR3?p|yL6KX#&BRxWgH zk-71bIFs8JMV`3`hu22mvZ;^Ta$R8CF=oJVTQaQ~CP$7X`6dirOLUV)QYT-m%+nXQ z6N|>1oMMa$zWwjuV4eTtRz7R{-`f7Sw*Rem{%g{9#8YHI(vN8T7gxr_ zeu*FVG62a2JF|+s&3pXd3gy&|bIi!V&ad(woL^x^LVj+w-a`MKKPCHraaNcm+o;(8 zAM8E!c34dbxWrIP5N>}${ zDu@nXwbo3&{-;F#XIUe!*G856|8OVp|9iNaJy zLm?CY=L0MHi(=?*URP;wzDbwSz|QtPKVXK_K7B!C2SjlAo;J)=8Ci=t{|KKaAxt5F z0+*o@F;SJ+#^QKxs7iJRiVP{lh|BW*y#|797Qn?^vBNlE2NTAw4x}un!^`5-q_({+ z$n`^j9Q8@$FFM30VEUAq?!_Fd-g~ZD2G}KHn`|VF#_j?HDGh5o*==4GG@VXn4fm*6 z?DZS@P0P0UD*`+}AD+%roJw)h_y9W{%%~)NwfJS0)o6r}$T3LYE7H1NqhZ_CwSY{` z&%Wl>yN(P1%~D$RiZ{I+%%08M+GX6xat#m3ks3z zx%0ei7RJ>5ms3fq?f=)m15_dZKU5lkpZ{fdXJ;+{-^OPx|F7l$wfuiW_kVnuTv+XI z?s|+LpbQ-i=%ANr5Gy&zJfSmOgoa9@Ng6d{I#Egq2H>Qa;DxJG#RPY51A(hd%Z#zUQi-6hD23|784|0DP1h; zG|Vn~M;KDi4g*S4FLbnC<>pE;Ls;-PaHoZFC95J8jk*_IG_1(|7T{bASD?0Jl7jE7 ze5HwD9ElO?s1{}%n#{Al+8|+_yAgMLh6&a_9hzenroVAr|9bxRtU0P)(4JWGODB;R zPTSoKf(V}u`p|^BF0@NT1|n2!*DlrnmY)j$Z%PPz%>$sS_+L8@gZN*M_SX8}t$fz{ z-&+4$>wl~1e^qBZI>f^)JME9>?epn$<-;8+<`!h9M}m;@Y&?J6`(GtJc_%#M#Yo3$ zU@`htRp((sqQdLhU^oU=g)sH_M27J{Np|V6Vd;}(j~?*+JtxUNfB0@XfY1>q$%8uy z<)K7;s6~@s9A3BVlirs(n(ue_9m58Y;jk4_41K8xsMn9&I~yBy;E+hRSg*H|hHDIx`6(nCtS4I>!6uP( zRg<^lBayu!;TawxCh)Z&_%HaWkpIlN^jFOP{$OuE%>Tas=;2!ayN%CU{#(m`Yx!@r z`+wYNXQ}k=^gbR1)=8D4Vcsur8d6jrb?071#Zlutzqmgbo@IG71^gXKxTOPQ9Lb+g z#$S%^+=2CAGlBmViC(;Vl{|g-^40SfKfckA@87w@x_)^0Pxeb+DyR{i>B@s5fgC27 z5M-wb8FEhZR7uZ`ojS0$c3q%R7n4V{WRiBIz=jPpplY$l50ks8XqLi>OO{%Tz7pGh z8bMss?4@~xp=Mmz+^~)@T!(MAJG1OeEe+X>VjO6DwTzKV9xbLfHu@MuMxc~ZkZA^n zP>u7r0rYCaJ4}=5lBB>d-A#jOJTJ(r*MDog`0>ZrKcas&l+gu_^pZN8d_s!;eKwqD z7!uY6UUEr|A$5o!%Bw8HNSzTIPktGBBX+qom2^m^bQx-C4Z-kYqHlQo8Hrdxzu%wN zb-(0byFmz|2bX7q^3Mi6&qnXgk$Q^ucIM^e4oCU%%Em^RFW8SltHr?HHdE^U}3PH+^MJ1(tF#R(JDSUhfq&{#LDCntfjhjfRB&Tr55 zt4RkuL@omwLyt4^R|g+w&6h-<_b%EU*JfGIpZD52%bO@PX=dEP- zARfJ(C-(v;hRWqNmOa-yxtqFd(>KRGJdt(4J8mGTagl=9AC8b%yb_TN1TsRxGnPpR zn0U=~`RK;zx#5yvAyk|-m3*o%9XRsLh9A^BD-_ZT^T50mFW@0A{pk7Xqe)#$q>ie!-j1lk)oOb0EKM2j;1S)@3t-Rnkyq6!LSm+3QiDv00Osk z>7RFJo8WG!-SRXt7n#01pN;c{s*56!+H1!i3U~s+#*1b2M3_*6mW&%fF#0Al39|*J z>M2}`SJhzb;MXzz+FAyC1hWnGnydAqin_90tQhTo6YyywIj@BTe_#o>ED{AT0p2pm z;eizDJo(aiXhppk8B;=yH%}!Sosz7<6y7d7MQn(G*yNzR=Z38aemFB~BX#4r#Ob#Z zhBXGXv`uGyF(X#qvh72?@lxf-HSZqzJve<4_)bND)zuBEU~-q^K0VRjvyRwkUf&zX^tV>7n|GXPDP;bA=fgDu$+P`|V;YcMuX zl1_5)0B+)Y)6mu^TTA?&*-EkXq7?gC|NP_c(ggwN7yv;gdG$p7;O0k*R;N)GkMH1t z3CM>Rsyb!Q!FT*g)(u*w59Ss)KX*N@AyBH4`1q5Zp(9rB=wVWdEmQqBqD#Q(kp~GQR zqyF3g4 z1aa`iuGqG#?eD7kQ9-LUCMnVDTBOqL>IpYha!?~23$d!1PSzet?O8^MEr}Np-TA&a z7Ub|ZW9XF&So9Mt_qu~4;e7_~8@RvtO`olI__vvJ#u@QJuo?DMms!GP*|wH z-1Uc_c$s=zTOY)!3;Z@WmIMj>uqL77b*Clp^1na7WV$2dB@rA$~4R5gM1#TJ3 z#@azdn{Ui)mtuh`)^eqcmzSYx!J<)N_X7K?apjb(f;0RvD;cf`pA?LEM)|0gU=ry)fX{vYj91*WWh=y@prbXKtnRAx z!bdE0;ezdNt-o?{}RUy;bH#Z^>EFyR|u?2dZq0iupv2a&IZ7@U0lC zxuV%1>TT+B^=5+UUY*veI>@F$uht}h*@EUGe;R0mf8SR}^d!h@OoBW*3BX?e75HD9 zwSJh-F6~sfLL_jdKuNP%ZzkkR&V;2y^&cI?|W2eo9EF zsQabo>sU^BHdhhC1h%0S5E0lh=Kt8z?HAsK!fq%dikp$i^=cn_Y@S{$@^iN_!9jI0 zc)#~ST&RLOesiYsok;f?fKE*{Z2)B z>4F&b1rcM`pNyu9c}Bj*a_D-C)6;DBo(921AP~bTYs^PeHQazKv4Z-IsMAHn!^1b< zJ^}j=2GO3u+g3s`gXu~8G|L8!VzKffw@(4uWIXiKpr1F0URXy*M)qr*#9J^c7}nRv-E(h!FkvGa-e5u{?Mb4(rL-)%@u8St zAooJgS?~!d14EGxhai@U9YY2hRVaovxnnOpRKvAr4oU&ywjN#Qm*$I09y5-*AN74q z-Um^>uevhMKJkatjsA8=8&r*O&e7{r`gwz0jJx`9GtGJ~bGPT^_)f!7?54q}Z-#(I zma%jompQrf1)Y*JH2%RYCRCJD!n{C1vuXEex)bA=-1a75==Rt5A` zLgU+70=|%Uixfp;koJ~K-6>C9@ zz?v-powsGG#HUk(9x$_0LG+>{h$dh5A1)hH&O|d8Mj>1k~@UWdku@^yj!*SXTFn-t(svYG$Rk#RV`*$o9AzGD zNX!@>oYOt!VLBVWo(l0W=zYXa?97J@awn>XVulHH*lqBm`NvIP_7@=%OeEQ(uf>OP z3f}}fBG16wM&B#7FwxC%p&f@Ncya#$f+a2T!$S%dbMIRvlR#;--^XfnYM}M~M2QaL$>QuB$&4NE8d@N(9K*z*v?}+|P(C(R zceHyT#DZSd>B1X^ESO_m1Y-al5IC0N4T^X{h(zpO3SppRj{Z3zY!{2Jl6s<;A6m>y zc?muuyiqK?kE#$xJktGwPk=8jO5M+1l6PEZ;<2bKuq*wyr>5dZL%D*kifBcyzs7jf zc2=?--reGnl!2yme_Xo-bH`!LxPSMcUYqd=P>e~~s2Dz%xUkMtNVby4I31FWWasng zsfArLaFyvZmF%zx)xZ75@?I`Q{X};fDLz&*%`b{ibS9V*imOp>?4gBB@-Iu>*p4Jm zEsJYSAs3b!#s12ps3a%~8nZXtc`m zuGK-B#f~aQym+Xt+Yuf*zPvM$)n&I{%YUDN;%HZoJV72@34sb*Jxyzr8+SegVVtZx zL6cuOw=wINSuimv(rB2Ey09}T75FAP5?P}x)1v6*M}q={MQ2U;sCu1vj?-?{UWnCK zU?IW-ioC=IMzC*+`mt1A%S|VW4z}ui0*n3i=akO8u=J#=*>sIbRU3mp%B=ckI8!>* z`PZ0RUU%fY!mjPE)HSB<)a>M&OsR^4uhYx;3IeA`UvCwmK^t6aExAU2rI0~MI~H?2ia+NaWOxvR2bilKaMA# z#!|s>x*~$JR!O60lYRAK_%XZqqCL)RMw(cF1+UGwlZh%m{({zvd)90cK<2A($J)P^ zX+Y{oWo>x_)QRM+so8LEc;*c^BPB}^A1E zSbJ?qRfD-?G3dN~?Vbmu0!ubdeSU2e9+I&ZFSzPiV@7Kud1OmDyBn0!U+r6mW*TaD zI;$p!=Fm+|LL)++7n0;pbv{)#yja-K*INJK0zmv&KpX9iiCY`9AvcmKLNnAD$BA-E zjT(-Jb1Y=*Vhy!zX%o4--oq{A-VF#Sf7OQLp%j9PYRi$my{+2O7cEfMFy0Q>)jO*? zfeN=$e0e{4Os@<|^?XE4N$Dqg#R&wgbH`qYS4`#6r|tG^|=+nXy)?SB9C5EX4Th^LDSI@057vZc>_GFLN6 ztO=D<-7O zfvd3VD(vYM!zMC+`#gR7?T;^>JWpS}e)i;*=P;}pai(FZAp*8FXL=Wte)r;7*61{- zhHjpIfL~@#(RjpD^bof33yoW{DaELFa#BRT=X|5Xf;(V_tKPk=OjCf2Sy4ilRb$)c z?&JX?p!k5JBqDNmc|_a-@Ltnk+nZS1$?k_(M0fl{`;8hGoH}s`n#^>H*|!Uj%*L$K z?ClWrm}f9*5x3D z^1h;OcVM&zMFv_PJ=#3xjer~9d#1&FFfi$Q2({;xZ*c%soE_8^=HDZOx#@9kGzfeU zYw5~P*Faj6`acvQu$>c^#c>&f)i77v35vdt!r`L1@WEu6WV{dEQBu1b zmlc@&tFW*bzJTx0RKXcITni%1Tpwl}9;0p9&5Z4ixthV&F+Bt!+`>B>!F`ZB!t2}~ zXE&^L>}0K$EaEwDxGOsDARO(w%nzkT+WSi>^XSVS<;mWusJj8;`4W_GT6!o+Ks#5$ zOL4<~TVg|1^O98$4t!@BW(`up{+#4(>Ml@dv(s=MH>ghteFQ>3?=|(F^?}btC&(Gy zSU2XtY57(Hbg;BTgWgSok)oCH-)*SSOs4axRE>*&493ygGKAR_`@xbUNQjgSAgrs* zk7kL>RXR!$C@h*$>R-3wmCRt)ym^KG_EmTPhyY3)2fdTGrl`4lKCDwEYK)q9H)hqAMVm<>YJcQ07`;vborX0CV6U$GewY-2@C5eiBJ&a2g z`J7oqO4BLn(z6Wn!oiK5;pc|8i5bYhTZgz9iRdnR+1U_{z&tfmS(l0y2sN6><$E8f zJMaMdsmjga&JLb?{G#S2AdL30A^5!dcBDjK{80jcj`e|e8qH6N`WU+a$=&4Q*C3JC zgS$kr1*zgL(eHNe$>Cb>($mdfcltA5bYh{gVwar69jDv6U+4e6mCySA&-(t)`uCaQ>weTnp-7C<$Bo;i#n%*R%>{f-)!vtxQ@bB=m&+48Ze*2}SeZ{onbHH*=$=iIPvBV8 zhLJ@7Q)n65LrD{I9OFsVsQV=)Rhe*^Pwe{^u#}SO=G5#+t?a-P$*JPYcC3R0r?_`S zAbWU)?xBFSCY+ksi0B=Do}s4c_vyRu-@SS9JpJ*-n|H6?GJB%ySfmlw2CfSzuPPqL z(Nb+eRu5R_@HxuSxR_A=cJh3Joi#1!=S$$`C|i#radM`!?x#usX~AP)CuTyy6qA%N z*eVv$538eOD3=Uaqlog@v^$*fi$?7Bh+*^!+^d;gw-*_35A@d|Loq30!_}XRdc!ei z#cq!y)9ZsEdbGZ6|1bS1k^g}W!037{*&jX?^8drV2mAj0|NXW6e>s(wU;dg!M9L_!>>f_TDo6Vt1`gzBg`)=dc5)!e(CsI3B#%yw*HPH}uY?wvO}x z!GV55iKp>r6zcKPK#wb7-d!HkyHQNJ{WW5B6|`k{s4qEbuZ(SxQ`qKp$ADq8AtXK~ z(UmcnFl9GYKhxQKP!$PYM~X3q6Y1?lM@50U|3hV#7P%DK1(UQKp^~wA{Zb~2gwBo?St$z;ct@e>})a0#&bM|KVqeL^1>NLJ+MXCPdl3$ z&4vJF0y5fjz{$}CGLA%ShojczqPkK4_ z_NVT}B5Qn`oQHE9HaK)Eel6VX;HlM%iotgna5uxlMnO+A_n(jAC0tJd zVAC|L4`0W_d8`E5F!~o+SI5_vMdDg1$C^}MS4;cVr^utGx@}0jP3IGa(FQ$3#9S>F zQw|k$TwQhKcnPdG>AU7&_|}?5>{BBDBm2_UcD**L&VP1y4*c_;GltfLIu3k}B+4n;hzG9|aSX^SNCV?Ug^!legWomaE2J+K2ioz*SV#rHHS~qQ|e$+lOs*DT_p71(^J9 z0K2zmDP*$6c%9=9TL=cn!Z;g7h*C|= zX2XHGBKh{m|JH6u8?>xugmghTX}=*c&DJo$3apzH!c?LIv5A9hVo&eRknp@eRyX-6u z(M{lkI(JGd+hD-~Sf}h}B3ED>sj5Y|@RaTMmSWeRRX-K}e@t{)y^X5#p9lNF`Op4? zowfdV8=tlQx7PpG`rk78U$p~Z>>OyQ{XFu5bE1pM*_rVWjB1F|>TR_|6d$uOxa6eT z{ETiuAa(ji=*XcFZ1FD#`ZhgD8Ty0*HBBP{porn>Cgz22g?29xuTNR`W6Tg<`-NooWQNlw3?> ztllyw!;0!Sgiid^M;4Vsl)C=8aY`?DNC!r+rte^@r&z^DcWe!OI2;6~e<$2~EZ~(> zl5z@UDlUd8oN^4L85CtIS^s`aT&c@JXO+%u2wnbQOotiK!}PeUYOvNx-O)#+GbaOu_Z zfMp6a30b^b9<)g#C4uUvAvhM7DDSQ6J72N?TlT%q9#g*m@2TBBu>bAsAFTKP+xV>a z|MmXA-v6)Z|G|@iM_%g_?`Vl%M&KclMehwmyu)!}67jbf2mej?G zaikv@jE{H;#o?)Qu09Eu2arQ}vrSUWArY7X7BY6;%M+C@*6YtfVw?^ZdpKD{QQ5~Tmsa>1B z<8*vj7Xroo@j?#~2pNFLg5{G%W|WUPX!GfGWo5z&mYtVVc}ic>+WcUwW(IbqU4lU z9u&d6EGx|)M+#CnVO-8NV4`UbsZ;okY>H;POl|%k8xQK#_6BxUBw}EqZz|DZQ2^ZK z4pty#H^S;7Uj}2Psy>pj-T;r+LsJ!{ZBz$vS3hkosGS<{Zyan810yehTmv~ClVU?b zDyx!0yue05A8;go>0SiG0u`5FifXb%fiFiB7oxzTGwzh*tqJu6rN(hb(W>hO3-Rmq zy6rwKrLANvW6yXrrSf$M8yOk6f`>`eVx29-5Qmbrf=6Q($w)Jk@%0J$%-m1@a_7j)9L|&>? z64=u-gPv|IRb@s-Mn*DArWB?2J--87J+@aJn(|9mZtA9V}V-_H8AS_v(fI8 z?y=7mrm(n$oYybh)A+>*6yA{^_H3G4$zviTgTA-ofcER=S1V}B+xg>jK(<6<1r=p; znzW){4qQdoSX-)UL9N_|G_6$y!0))QTe_*Dda^Mxo#LA5_e*KN-H2%QtLD}!Xh`Fy zE|qtug}t&(<=2Zh2Fq*=y=rIzSpXzxxC{srlG58*&@;2Oh}Xado$@UxALmS6NAxym z$wPMmkZ9v&KnQ+_Zli?QIq%#Y`vS$C=$PIp8-l8tU0inJ%xV1-1>c}&<{8?J$2Y;{ zBn!MV#4#hpZ+xwC>ib6)mv%h@Wo1{mob-nrB7;z4TBwj8M@pzKsv56V(A02rb)H{| zUYN2nGz970dcpIN^v#5*&lwC==}KjLIGVMGmxDp-EW;)=q@C7!lr|2E%4}@teu|kW z%Mdp?uof3)pyGrAmfXEvK7^pG*1W_pX9dwPbI&TarfaMo(1E3z{*;Kou^YP^@<7;+dUaD-O4ufnM$@kJvIKKDo66WDjj)nDPbh(Uvn09HY}RG4Wf#%q+bK(OFt?yS^`&U1%O_+D72Y5o>f6?n=+Oi~^=fONZ)qFlghlNhZ_7CjueYtFgLW&N zUN&snSC*aj!xsmLo_eD%+yz5tjLqiRvCdpXC$! z|Aj&8@7qSP|KIMjr}c&(|7o|`eDweO5}!x^zeoSSNB_Uo{Qs<*UKic;#^d$k7_Ta; zhkd{TRz6WmihR@s?FB@1D;ix^-#_p&h4`w(Pcswjo{wCC+NkWP*!AX_ms(uCIEWOC zY`a>CIMXF{OgG5=6kdQ9U9-%fvm)&&NF`L+mA!2pCPu?;BQqcbb zqQTSXfGIQsVie$0Oee1)-$F?21?zL1Fk|%iK-`LkU2PA~$L-mupas}5Tz&plJjy); z&MQH*^EdCnH%Bxqb0D1Ch!7U{g|`$e1t(IDnHyu+86?X~?-;J-+6ZNM3|1b9qUvSP zxGV{Ts)5=)&BSpBCYuKp0=1&JMb+U$ZCQ0a7Xw#Dc+h6Q!DySubc@e4tC{`*nv=YB z+QFma(krbx(|IBd!2}5A3?sa>SYemM0)RzxKEE>BrXLO!gti!uzyM=LGc+m1^gyx? z{WK#S50oh%vBdADP>KcGrWZ6VX@SMdBC|<~uPRllm(oic0W`#+*>XTzr4nDU&5EI- zsY(FGpDt`u)f&dOj#7i6wr&%)TSxpb-+Uf{R?CA{TL_K#z04%>pTjL{}{y=$*LDBMr#T|$uEY&L>N##uXaIKUbJ)CEF z_}7_aQEsCAis9-~u!q1?Vw6F7hZsHsg6^(*pxa{j8l-!6L;eHPWl)VvgwmLp<{h}G zH|tI1Wfrb7B|A@WRGUz(%HZ4{_ow7RoR(>V;L*W;mCGC*;lCQ5)wodf!O*+MQKhi9 zs-ES$slhm+++kCf_h{=fw=oV3Wt{XDdxj2+1+Y-zRdZB*7;6yQ`&`XfO~b6way^U? z&eZrw8V65(E`OH~wYCD(+Cr#XTgJ0uYpbOGU{R`>%C*|EmA8mYm4%(y+A1PStsIbA z?arU3>>m>qH%e7BrL8+nj@qG1vkD09zsUv^&`XsR`e)+m&KS$?OhvB~0SE;MPdAlX zRzfPz5xosHAN(M6DBy0eDrtTGqK*Zvrd6??5N?(n)6^!n<%6Qf8_93jl4({^hGbg+ zn6A*30{bb6K}Gl90I0oFXWYeuNa&qG^0jJxUnT+4fHVw(m={%1^_PcD*S%A_2{Y^( z)MlJzL{ZD5lFb7^@7~k&@0SM$4AD0rBTh!EEP|@4T>~pQ4XADAifyRcK{Iy|4~C!7 zA;9eZ>;%LU5xxEU`6Qv^d}ksWhT}aeExeHs02-Ez03hHKFOfrAmG*RXy_>@?02BU| z+c{GWP-16>$j(zNPHpVGVnA-k`rVUHs%lnCfVLF@&VH5VI3q+Lqd4*4h$o)^Y7{x2 z9^({TzaxR(WhP)o_ST-L6$iCB`)X5pW@4Vt1(K^qwlQ9|-i5s}Txr47C>m6#* z<}_Hw4p9+4&b{I6l;ep_tDPe(^l}E$t)H`@M&4LEO6q~yM+;E*azgv+c->8bw{x$a zNFS{txBMmU#|w?u>YTXGFL2aU@(rrO-{8O48@)C5Wyz3*FxYGlK4Imtw%!`?x zx2vPc2eBNYuadJc@#0t)dqmnIBw{q3^6fGjEh8p zt(659hZR@lmek#h8d|6(3TO9Hif0Z~;)C8Lklb~J<$tSs6W5)1w>?Z;BP>SI2;Z&a zKO|`JXO(`Uq`+VARggkjI1ro_G8Tl2Sl<(gmV$IU{ow#J*!~35ORv7|>qYDDV&zv% zn!}%IHEP+LKv4xx7xNUg=oD4@7omp~z(Pq2BIz4_}MAQ+U=ax9cMe z{hPXcR5+53&UNQ_>{-OKlb6Grs9RFY6r|&Gx=E(`A6aNz=|?vs}LN=P&^YW8L;T{4rvpc$E!5%ufH>pPqLx?6GU3pe9m=rWo5hyf4G! zPqYbQF^VZS!cY~kxXpo4tCWM9SA9WelDW&2~HHtGr&16O!oog!iZP`3o7a%m)t0M^uos2an~MM!QH0^l~fZP zbRZ^CB=n`M3?W*&cKg~D@^Sydd+#evY&36={vcc7IB*oAc->TI8D4y`Q}1Sd5y7Ni z4HjOqG>}A~3k}Zbno8Alirb459vJiWXWUsmiAT6ID+qeZM({PnM5(fpM3ns4rxGuv3Dd zju--A=2Tu-O;O4hoK8I>Fc}ru8MIvU_X13fZ7Hu}eiai%!i_TFRG=~+^?}Q|k!FA8 z5Z3_+r?M;*fw6*gXCU{G>K=f_(mbs2QW4fkI%uAoc~3t#ii^2})*trSd6Mh_96eP& zi)l*|nm<1hzp@gQ%DAcr#Fm1=sRSMM-J%ybK58+_Yk;->S@D9F+t=vSR!xk<;otSP zTxF5$pR{L(uhG?Nh*syttbiH;CqYRgfyO^pAZjROxr6Q(y)d*y3@=X z3;Kcm)-R-yCO8-f+IWC*Dc@KQgK5_b`f-M$dQn}5LIT3ms?1-dTcH-1e zoo0$$20_zdufJuz1U2K>IpP3a5@rra>2^p(;(mv#&uh^@7=iP?U^D4!eC5pVZE|&H zMSv{?oI31fmu%(xVUO3)s=4$TF%)!pR}# z@bH{}U!P*(bY81Tm#?iYYdXI3Tcqf|0cs8J)X(uwvpq6Oi*&|a%E8yhNv`4r5L_s7 zwgdkJyA1a<(_3x|P6k2O{zLMDG6z@CX->=C^Rbb;RM|Mp43i!7lG!hH7P=iyQ~xw{ zWmHqO_#Nq{wAPd7M7|VeYxl=&Ex_y{5Iej#UWYzf>5_N>gnE?i9`X=9pJRSE=jU9F z5AE{ZID@{Ym3RI3QG5!0Kf6I)}h#<_n-Yt4$m#7l}i)aMWP^5==yl?BP+#dc=VSaY-9 zW30LReG1~geZb^{_sjgwpGEoKcX#W4{I_Pa@fiQ@OMD*Vzdgo(dyM~9I{&*X94X|R zAA9YIcO>|7c=N+>_MiRi`j9hi{4hKj;nAR5jNknkG??er#3?8mP;ptN(2U92VKkNX z^>*K8_Q=WDg#lTN2akn8>iT>;gBB;S($BX!FibD&rc-mKZt5N#xepGWNWCA{=_qpZ z2S$$X=q-<&uS95~{#&XSx$8d$7<`b`f6@Bi*lRv*y6b=A`Sa#u{`W8Pd0hV=*Z;@$ zzx4V~Qqf7semLl#!%npo>H&_)MHvN;JJW1$x19~Uqn=K+VIm0*DfN>Lkt4Eh*jJc+ zqmt|-Pb+9$XtK|=SyU6%0B!c)p#g0Dw$KBd2eL6KNc0Ga9wE^qBr-xGBP23HA|oU+LLwt1GD0FFBr-xGqmE{#qZzf4Q5zYxkx?5N z4;!^{LT#K-8z)cWouI!a`Gt(m=!hChY3SGhIS&q}C*>!T&b7J;XeW6^xgA>ABM_P_ zh>oy^x(-!E>$!ehBQoOIYS*D!3Za|>a#N&P`9zd<Pi*2Y7gm+5TcET?0g>|&{2dqfv^;*fjs7G!U^aRCax>%Xt) zH1?ksmId+O;PNk^xH|IyC1qi)=6hwor*4yf0n5~Mjt-*@0Ji~r_Vna^VXqUeFDRI<~hyDbZTb@Wx?!{bTTQK4|CC(V_5 zvLtVOiH;YIc!U<@HTswDzx|JtC!RO+D9O*%$_9HX*XEdicWwk&+~2!0PQJ|-X7+?8 zA|lxh4JzMNWyKPWFDpk&%1bL^12=v;t;CC?Tu{@G*yl5S23YZkzA2 z+lg{DLnICpLVwCETF=t9HIBNWPTh$1O0ht)u~}#Fm@tqP1${U9Iun zw@l)TRe-WkCN$>v2_07UR3-uaCL7 zGUt%~RDhzl`zqS|+>cj6K;`+R7@>bWzX<#+{hbXedz<2Ls~y~;At~aTGCR3RCiZgp z!|di(;IU}`R_CvO!;|;l$EV2uFPo3Qfd60P+1~E6!2j>* zc9EFT;JiN^UpEhuGty4rU%NGd9<<>d@AtOJ4H3iLb-HIMCWg?VE`l@w*guQ38mCVk^AL}Z#G-^H@v{8(;!eyZR zcBj{CpI;8rc{Q0=wkOlm{>dyI1Ml^xH0A4+?cr#0-WiyUdLc0Yy$+Gr2N7c4<&C2)LumXs%;=ij zcy!&g>?qaXVzwAU_fAqfOPbI2D3DcE+|ZvhXPlW!Riscup=AFkY5rn+wwci6p5rY0 z<*cIh`?($4X&$oifj=SZO|SuS*-CMTit{?0wPzDpE$sETz1?(9ZJ=S~h>y0;Fm~ot z??BFyEhW={mlrlRgU0rr0uS02-TQW?L4-Ynf@c`=m4#Cg@B;FvLk$YQTUN43sYN5| z3X#rC;Z{?9uap&Q6N+yF;Q8kqX_+=&y+S*izRBkfd@#D&2vwezciNKkb9SP9x8uBA zz_-ezVj-YG1yQ=wqs1U_ATEdfi%T5>4K}p^?94ZG>sy`DY^Pr7jjJ|48HaNpX|XCs zCmBMU#%5Xb7g|QE%w6>-IUF$seyAoF*2<2pATXf(vnG_;!&etBi*_(oK5~T7=g-um2S?qnGO3@iXK9Ypw97m z==&TJma$vALiC0mO*Cd?ddN4jMTQN=yZ_$W_C4I?E6*CutzAjV8xu2eF4Vl*#+Z+L zyXdX-ta;$nBxSL-w`(hr(qSO%PDa4niNn)OD_HkBf|m4v&n=4oGWk?^}Nr4>shr-YvLImEYVNfIzGk;^NVXl<(4k1eAQzxz zvxq>$KzWSr6Vwj% zv9|=V;LnQ!f;CqsShF0#erb3VYdREr-i%R9Epm)U5{lnTP(hF+)2Gc;6r77-qG!sA z4y*C7>#l)X^v(6kcSfiHqFTW`qciEbw>q0J5w?*!9+#bo^D&Y^^`xbx^1`EBSJQNL zmG*Enq_0Bb#Dh0d5-bu8gM{*wJ2`O+G@-zmctc1U&5_kDLq`yv7$A6b-qrx1?QI}9 zsCPVmXU+G(XK0eHxf4@?{qPu%NU4-eEDw?u6cPg%`YcYV!|;XfA&V?YgE z27%>jmMI_brc+wiyw>l8lTdUjdNZ-?M0_HVLnFY~iJa7^99MOf{iG(})#OWYrNqZ= zBZBQrC~GQ&j9&<)l-%v&FIOHdFMUeL9o1Ye%G-J5IdDg4+41;TrtL*dE7p&#Bk)*x z+;}ztC0zvpXYZQtwRl>aZ$pEi;d98#_F#IPdf5RgDTXlGtf4 z#yq^ZRqftYO?aCd-Fwa6HQqy~K@)d(VG8m1@>#am%XE38L}wTGHLssD(>d8A`#tq^ z6l>L+Z)-%`Cm5WEg5aPUu5rVV&w?YgYB4pr@2muy^M(zLd1m#%a&ru=!{^*8?GwnW zrgB1&mbjR<6K&t20V=q(=`lp0X(A~hpqieWtZ-MrQx)X(i50$t5orGT7Fo&JcmVUkh1kZH`S0WT@8kJz>GNMD6*=%rY^e+4JWoOch9qQVjOf7h% zGE}|koMhio(wPaaWj2EXg_MLPqHm(p+WbMA!Zlv4hn?;W$lMm@#8I1**|fLEm(x=| zue51uWMVqwYiq#ZKH3}xy!rOWpT2K@|Mwr>8sJVznLn2Q;fD3a5OYAXCUDBm$Fm!0 z{-i}(xs{7@@}$@8)M(sxU;3@u1e5(Mn6;c13|8(d3Osrk5Va-1BLsbaNcHq1_4AIC zJiYy{{q`?EfB*8k_NyPiefi26#!ZF+Sa9HGc%{G=3?!W#&Q2#8#p~{N28RM{}-+Q z<4Nbkc_$eSyV;X48k|%L3PZ)&pfRW|^k+9M@ra$N!#FY=9*zU6eskF$^l(YZNk0Wk z%AqkPvISuYtl^ zwUyect<=`$N^Nbf)Yi^QZT(@XTD|^NZh7T>x8WCdj}3=8LtO8~;g-QGG% z#nXjkD5zLGy==wWsx1Z;%eJ_=YKuX|vMuhc+TtIID;Ct;ShdMdt5*DF)ryCQe$6~q z-w=}{ua1b6Zj!CNZ9VbRayYZ)ZF1wBA7MCtczi>q`??o@Js0X)X{c*UKs_uA^sqe4 zR#}*>CGafW`@yymY#(c)3;8 zokY9@&R^qeNxW=R@c%|$@zZP`0jumGC#-nKUIM%f9vw%{GQ6#i^afEu8d>C-tpNBb=XpO5Ys3|4G! zW4hT?r^FnA);5~Jv<5wN(3xkwiby`qwf6Tr-HXfq1nBYc&bXz9Z3Ry@R7Pk#35)hl zCQ@F$wpy>lic7Rw2E-FhzJw^}CPt$Z(GPf}jDgOeIvxz3A(8E=r`m%oF$RXps$tMw zCY|o=VcO2-Fg=GKvUGSk7>tdc<0FFHRgM{40-+;t=OibWw8G;zKwHfz7~m-s?Nyc_Cx`A_Jb;vUm&q#~wV@*6lB%ZdEG`-Z z*BKzV0T?>qJ&|dhJrPpAuTh?HL{AK97yv}PEa!-G|8tIzlW1`*@H)_L0UesDhi^Aq zM9q(i#_GU-v0O&Dqyfd{vVQH$W#u_dyqL|$6WZZ_^YZPte`&w@;eWozyCC)YK@^fN zzyaHK`qOOUQ_@1KxI){~Z3;V+tcR`y3;Ayw3VBfVjQB0qTfr6V-BG3yJ0+krw`iGN zBd@wBkk`23R~$rGe$^EK*ZV)jGkB7_MwkMz6{d7;e|az!muR&Nh{Y?6KPVN)XD32_ zJt~&KMEAG{GuT)thnD^Qn|?Ov$(w>Xjp7Foob`uV4%vWsge+aor@F}Jxg#zw z6)JSw+bSnea&GR}V7IE{z{ryfwA!moP|o)4&U|wh zEzyyMqRql_WV8*&Me%T`3x_3l2;X~g{hYnzsUG|Z!z|sns~D6-D*=M zQ2Or2#zNU!j+X-(2$)N0ih^uFgLfP6QF6EFvFsvhGk7xux}V1S@$oLYRM>HL)S&}! zk}Mu+UrGKLDWg!hOEpWB7~HjG$4<@A&!iQ3jyHMDVuN<(2%y$T zwzsiK{1Iu=I5M=t0E-;)YKj{{)Hj|)!yHKqs7nKi+~bF}Y-=j;4-R;T22B$Wv-#{< zMH4Gk#VeX>sj0#mRqBMltfOr~hRMWeLG(;T6{NVC^qat%D(WY^_A0cFlA3y?;<9dR zuqqeC@w8tnn485KmxdIwjKU2$8(AC7EVc>O80%oFPi){r+&|lP<6CGM)l$~OPzl3q zxDY_ia%r?Wve#hrp_zlcgL5RJ!=~o8rGxE3S>SNoA<70*4(-S^gTb;S}<%E7bST^z_ zr)cH7zBZ8HN4v*R)2mWqZjE1I*Hj0Y^iXPP1h8g#_uv_jArIUdd97T7peXbS;it@q0+vfzj zJuR#ad*WDSz${W9Mh{l3z8t1h#%B?Sbz&g@hvJa9f=&@vrvLD({W#1bwcu${rPrO; zkxD>t&-RbeS8gR<=ZO<8jE9CNf(;rYYmWqak;;w2$`ryy1ZG(<{{HgE)g$Z2l+%kW z1x%44wi?+OoK7V#+Kmh@guyQ3pkl$*)c8qGUL3~hAgl;2FN}l4MiHrV{$OKpA+8ya z3>H!qNDl^O_Zgdr+-y-!95r1Slgs*~;P`8@L{-Od1eElTCjE%1gBCp|SYbpjRe*LI zEN`>H&AzTM1$7N{v>W_0Cr!7`Uk@>eWF51Y(st|94Xmpn@J~>#!41r=N3dhV^hp_p zmxRq#b`IZY+o*P=xXZm9cKOLQZF3Y8kfCd;>XYC4O#-c+k6^rDI=S>)HtL!2kk?Bq zL+h^)r7QwUx*$X%zs>Y8iS?Xpa1YR*gGIsI?%mCZQ}w^8#n1gLivM)_+2cPopVgm+ z{@+g@?SEh7^JxEjwEsQY|5mgA9d`Nnt5qD>flsjHlfJt5)QUTk%j--zX@dr%4I;qaNDeLm#6qlJe{g73%~R19Fm#Ku=)G_c0-^Y)0(_0Ci7WMnKyq*{plo z?(}+TBgZe*`2QJ|yqEc)^wmoXae8?ihp3%KDFmjoS3wNv;w2st7a$5hmqIlPGmdc% zXo)iv(f$-xiB=YY|HAwi-%lnm6?qG21~E;g1n><-ty_2N)%BqJ1wSVuw#>)9G* ztAzfFVXF>>Hc`nwC;}5fA|Jw4e=@rS>GGS8rE<|=zc(6|QZA_!C%2*o1@+3eKYsV) zexi=U2^!fMNV1<`sJH$}GU5pb3j*fZ>~?TD7}0@$_l!|-t7F7;^}SK?dty4W$(MXl zta{U9b~+hd3+@Q_#hgH;U{)>gfp=z;wga=~=m7=I8&XlIlLAbrir0dzEHRPHFH#k!bLb{ZXl60omCxhX+`~oNei%_&xcW zChuE#q-yT$+$~%n;&7`;xM&EJ5VT(X5DS(d?2Jk{6s|3r8OT83v~Q$hS2ws}vSXlc zDXILrI_#dj>Np;z=GfF!?ySPUKe&_R-QI~IC1HCm*zn?E+uA^dPB#W$w}sHROkpd) zw~b_?E08+t2!$Z z?s4&+fJ#me+94*rZ;wt6-&Ucvaag6T?@XT=GKs8vE_wDlgo?Yx#$m7jz$evO-lBW~ ze3emY-M!^enpg9v5#eA<76saT0xGQ)bp>4;{P%CF$=fIyRZ~pN-VI2)RjKJVVW_EK z-kY2_)BK5cRcfNSei{LkjCSgb+6?uG5G2pHaP}6ly0^577&xVQzuchRX9nbqnV12+ z(e)5P%K>v_Wzh_9DIXC&i^-_y_0K6Rw48SQmP$#4!fyXd&3?RZgE)IkQu}ot%o35iKSuXAS|M_ zqOu_Ecv2PRlp*d%^2QNq%e$ytGlk|$OHRJ_q*!&mmytI@7gq};9|B)D>lEAh)D}hh z1IlZh78h?XCwG2}x{z-P`A78tH^*TQ_#$cU4N~6>%6AHL3aiMQj&IOxL6tSXN}jE? z9NF$eIDk}ZiRK-{shVebyO79MqgFxz3WTXts>DXZ?n!vNf8C+bm$Wg_atp)b;d9yr zSfLz9gTcnT&x{{-HK$n7j8fUl7Zr1JoeSUE zh>cl@EG5KM8X0F)-fZFqmi;36{G%Z`0p8VGc#wsMSmFXFnP^~CgmDJY>9LT zOex6oXjY2qE90NXh`$ub6J|WURmG|M;DV(9Eq|gehmkjj0u%E6(DM{FJIMS%g%Qfx zO_phxpa()DGFCzEZM9=iJzoO)T3P683!pp7G(&1sEmU>)Y|_}KGVuE!kaqU*^E>%0 z%K!KI^Zz#BT|LbI`-`~%h@^Tb=dB-#Vl}Y*c zh=Qt2sk(kT|gm$_{Sz5&18>Gj&P{_rMUx{ZST ze|{fotMs8DQ(#^nYWHizhdazZbok3sFn=q8IT(HDcRPbN%%Y_M7i2-CR_udYWj*5P zWVa5b&Myb)CREQKk=t_Z7mNtB0o&BkWYz|0zC3Fcq+s+qdT}|LQD3Q}0)bJljY$?a zZ>m&Azo6FTgB;ATh=<%VIUDbbW>vyk9pw_qDG5<~@t%Pcp;$D2%jAq)zU6=@4i*ob z(()fMg6tMXj-=2J;Uz|N*H>5Y!Msw*8R~)rn(iD;Hc%*+n2ZId|X%gUm7R!$#utF;8^()l}mv8pQGILuY9(UKWI@1uQ`%nf>91*Bvq z(fjBiC3BA6TMa3hqVz!*_jz*UFYqN3o<7JLUouDP7h2|#7~#5EG9BwfE}bRwxGpEc zOXhf8PKuYz|GJzYUz{8EKC*mq7TFcVd4Ey5QE5+}*IHP1^QMwtH<)T}T~XD~Na~fw z*AN9r`~+qJ^sm~kxtvns8dcVl zeHhA)*5?Ni#A9v)R4j}1Y+xxdpWpYvD3El&3Pae7y(8JR=ZoJLN!rzC!oR)T>`UH=pt ztW7YnRVA=~Fj>c)$rPQgx&Zn(`+$+ostE=fsOYBXMz;6FX?9MnO1E4OAE&S7vl>g1 z7N;|gkaS`GTr+0Tn1`yZz5P9mc49vGMaR=LZO0ynbS2y!}=yS^+LPEa>=gm zgEP(A6>$D?*|mTFpWO3*Jb!wS><^31|Lafp_UeBAho{eXAJ6~4#OLw+|MC3)@%(?8 z_;2=jpI7)+;kkX}-SH*HhK(NT%N0^ZL#11Kd%Nvy*d1YPVbX9^5!lC4vM2lr%bcu@ zjkr}wo%t(=cVmT+5ve9tMVxf5)#hDQy_^h02vxZe$JNz^FW=q^P-%RgIJpuO6bBDQ zH3bC2Ze6z>P^fMIq$nVZM_Di`BJI;AYJfCcsuYjf3Wya$Tpq(*CSmYpm;_m_6yD!Z zRRzXrWmQV#LtLH`IXrj|42vPIFjikcA1%uN)&COle;cUtJq`Uon~(b6m-syDe~Q1ZT16V+VQ27RGy%-d<-_iIXLjm52rC-bQ2{-C6hJX- zHd#9K|w$j_}!3a(I8%au|TvJhuH&6SyHKwN%!NV1Xp!^HsU0q>J z@6*+-<@=gjW%xa$1jIH>W>ca z3My&(7DxN7?x}Df+eplcWQCGPN7vlaFwgOYoPtJevcqY5*46p;y zQ|u++zNT~8Qm|_afU~#TNr%;GzoEZg4$AcaluU+UTk|X^MsEZm^CRruP6nfEjzOFo zM);@6Xxzb`ev89_nlZL&qwa+7{d|j&5<0A@J`6?sEeCRIQxpO9Cgm3&pXi{g)`#ZZ zdu;^nYchPtp`-fAA=lP10nN?v_PhRj&7DDLa|fUdQMD9U=op#@{iy0#%4^vajEB%N z#RZ9S@&RIjgC{{;Af|Eqqly5-O1A~p{)leM(V@pM1$H6QjPP=J15f_5pIy5Q5ZN)j zo$T+M-`?iIyyFLVa%*B|gf67@Y_;TUB*S)`rSwXh^!gv5QPQ4qQlWlcKs&KiL+Mt^ zwY8s%9s~02%mp$uV`cPoD%@8oTP+hOP?m#F(?ba!cA6Sb5BS!W1D;$fWWiy(R@1{@ zCV8@PAaYYyDqn+WP3?zZ0lQ(;A}MDL73!v_mz}nazw^o)Y@O7!5>XC-aS{n9cjAX| z5yDQo(HMv}D2}T(39NLgPv#Hus?jUm6F*}nb*$YP-iUm@2ne=`O?r&ut&>H&Mer^6 z$Idp;W5%`=s{2tuat(2dF9wQgbwQ~oVLUU^3|hMWVDzCq8ZQ8$e5>G{Ps2vg$ z@-584L~_Nf_gWUT1gOj5;)XRpu*a1iK|TLJ3^fox{v9TL0ZB*ijCJL>Kl96F7iBsx ziw2!n7~&NVywPH~;6^Lu>N;KQtpcVsb-E$qG-6su@W?q~8MCvvb$N_xv@&swER<1=Jy(iX4~SN{N;Fm*)dGcDi-{BnFV%ckyRU?(^{O7*E`{y3c%sZ<>kHghCKM-t94?TEMfH-=ilar~)49nVBS&C@r1xS}~L&%>Q ztQ7b)uAQg_Rw*epm2(-FYGpIU>il(qdecb0HU`xYYOUPKKpyWAz^nQ$0 zZt{yx@l=0NdEs_!1PtGNiRNd{t6Qoq=hBNi3U-N)^OR7ifu{rmgAxr-8psCX=^;I> zH7Lgo?rZDw7wSA9W(UBgX*>$IU;O0H54iW@vl&&55TJJ)einW^2RWGBe3{LfE(N^- z&5U+r_Mz&_AvUs!4&`qrt>inJM?VaCJnUk9h%Y-Ni_nwY-ypdKKSD3^H-~C_XFFQC zGdjGlGlb1X7{hB^WZc2cYAYR93egeel}%TpSc%~%Huo;~;21V7|1^WNPKw}$(}#{e zNPeq&@JKr8U0kF@r^X~Y@ z3?3Sr`5ST%3f$3&YF*!}2*VhE)BpC{NFd{lIlZp679`~hW-HM++70AtX6X%7+y&VZ zj=5;Jj-PEu3v2Oc5(6j$vKQD0h7V;PFhd(L5e#h{^jON$LUTb_*D(}CnuX2VAe&AN zP2%JgaPNvSbGQ4xRFZ;YJI^xUU@ETbYTS4b{e~*}Bs0KznRom5i!N_+!yIqXA&=Zy zJ0w>7>e!yT0G!;7ANOYwN~;T1`X-k%RL<6aA)TF|Q6yc>D?c8!d2u6o_-1=}kSpkJ zRuptcIxKsL`yx@6i?=7$T>c3rnLED9uywO7A8Q#=9;2-?D5*)~AfSz4F$C^Mq}r+| zX^Y##qqMOqN(R2Q<{j!&S7TB83kppXO z0jx-$qPBZd86(E~0?b0=KUBOe8Y7;t@a?G?Ep5}M_VdR}8}-Gzr|MlHj`GOCh6cOUI8Q_h>*((CKt!>yyTu(MyYBKV#?Ci(9Xmj3yxBAb;St70_ycV z=oHAUKNOGy?los$H>K7e6CTb-*_tl4)Ruh_C{*hffU1=Qjkp-QKDu4IKmjha1hFUgknkk%w24Hj+@ZKrHA(x`kpP!n3g>J6AP8FUJcN zIL={Ihu$u`h*LwK*)IZhVmUdYqs%>YKl5jjq;4!WtGoJ%lVW#5#R%meD~p9Ia;}^= z`(q%*Iun`l`Mw#reQq3hv#abpg)J%i6Q&D*<(j8_V0aYlp3g45MK-6&285>@m_jtZ z1&x&e9g#QcK>HrOaL&Xdy(n%g9%J=hZRaq*Bl+*yXU8AMw%dp`hpWTqX|C4rnI-fJ z2+sHmm?p=kfNOhPd5>mFHxhxKdywrN2jly%Lo5}B`!Pa!81#i7M4k^sK_?v-3ash% zO?o%n)2pFqzv264D9{9M0aob0@P#nbo)QbNlin5g^r|SpEbt9k0xP1~m%*$g&4ky; z!+4C87*jo`xd8^wFc%<5!4CSfpJtQfc>FmK8gG*WI{cfDRs0@61lzY8$#GeD#6-Iv5rI#S%;3=m*Jl!@VPhVgw)LC zA6GRvUvB8!V5q&z^Km3TDxYNzlE4?tiNcF@qdrTNANijCN*0C}KqOw-yDA~0_idB+ zk&R#pPc&%|h~v+1Dw6k5VJAX-WgQRcJp8yy5t0$~Fv8#RVA&$U?;-$3oHE$hohU?oKHJ|Ud9js&DF z(}H6$>Z8Rd#nKx|s)@_dBjB%F1xsNr1Ivv@lie8!ScmEOe0_?cm8f54y7437t_`EL7J5+|LYRAR8iMMp zy34!-ljdK>qPCFE`UyEZefnfdAQy=%g|0YJrg`D%c96@-WUTI;Qy>VCglH$W<{U5Z z38Hw0cWTeKbuJU_E(BfCcNY0NX*H==p>Wh)2s;Ka=mNeRC8RS_|BRe`4l*LA<(pWV2X4kX zoc3XCx*4QQIn~S1mCK9`6!o4MMvA(3`2>@PGNyfj+UG(*u- zS$5^Ris!GIbJcBo&p|gjMRLYF9B~cI?R+b`$gbMU)w}3GGhj*)E+1&F_zHydQqnc& zChLA6%CJQRkqsIHF2X?KpZtPz&~3* z8Q}om1H(z(TUUhWMe4rhhN#lpy>(`bhPtd_fZ#jE0o(FtSiV=~m4BVtVgw{F5dEQ* zPgTh$YAhBK>|cj6zG~-Bm=eOah#t#OMAV58B2EhKK%59`pbbeZ7teh=`(p%iXXsLb zsm!vryb$q4NL+L*z2VLajH5NuFsu!~xz$@Gbj%#`K2FcETl{@%e^2QB5GKLxP-~;E zPJq^wwcFrHt|=r+Tdj>uhR&{qOmbzaTcrq!9Ogjq3@6aHaLW;zP6~H^LvM;{N7Ae4 z?pOf%m4W;UK!C8xukJj>38JqGY-k|Rm0!scT1}j1@cZVfii4(}{`x+q)XJ49qy!&f zm8XU|VF?dTZV1>v4Ph4HMo5XCItX%49V8zJMF+LhzNNndA4Bt&1c;LZ;DD@xziZOz zyPVjI#kn~mkYPCWvPUR%=Oj+rH(R#rTrN> zH?pbNsLRkzU*bXv2fa@~ompAT_oZee(#|lqgZ9JDR(~@enHTq&8~8b%WSz5^F(8L` zku-scG6>{nY?Ap4q8Uqlj-4DuCY$C|yKQR9efkwXDZZK02n+~UxaVJRpQqN4Lcq1+ z;h{gj6-UVc^e{Z9HNCq|B0CsF=9*5?uavqSLCEij)0J!L%9T>6i)z;z?jR$^AjqyY zb<|9()%u7~-Ir%bX&buY%8OXB+^NZe;Ev1i4i>{y8Gy0@RVg^svM%f#b;E~qm|sU& z30o~jcZ0{o9By66vn?nQJ=Q`#y0E8OD#VY^9{z9$o|k?ZVgpg*kl5aw4y~N%w;}7v z!rqwUHV1IUV>0e*o=G_px5^*%NUXLJ1D*a>{~Mj6}MAJ`^BSyN}X z9{vG~ySJ)SuaV=al9Nui7NdU-ot-z-w~qi0*V9WS~OSpW~X8iYugd(0VrS zW>d;r<>CQM*6&ejD&u!#gw;?AtA@9-^~tAzmc~Gl#{-QVITdy;5Hi7VNqH0Rxw9#} zMh#6nOua`xEC~=~%~j!+F}614#mBYh7cMUf!?0&;(3)K|Y)`{u&U~AN0s{qtus{Nm zuhfXaOjsnqzqMMPT#$NA{@NCo4TW_ZQAttH6%9p061$Es*ZN>ymm_@%xquYX)umjg zr@W>GqC)*l!p+h2aU=BS5{gto2Od(XT3ma9Qss#R?5R5v;*_^myBWU!M-769TB$*Z zqMld+mQhOM)Nf(s)ren<5#Q3=?m4u2h3qHvt9ZZjSq~Wx`e|t~mxH*F4Rc3wpj!7zAkjcxU7|!xbzL8GWTtawc_+ktlT@Xs;>nLHsh}^YVC|(u(VRqd;FoUA=Z*JgYJpyVK z1X0zmB4(B+e3=AfR=y$VlBYo%4{kp+n7mIQ_EZHI8C*mC?Li(iK5mbks(7Z4C()yq zjiW@`Ak5UhMPYJ_OL5H)lkK0}+(r&=iXB?+=doXuMa7=z_|Kx*R0tmm#pDagC73YZ z#V>v^QWpyC+RfEscOFM3hY^Xc#8z`Hj7_7Y#tmz&EH6mFfmFfPVVv>hq5JZXUb>rv zb8^nTIxvq+hdBS2#aN!B+W=9m9MSDS4PaWgm9^N-y>iaXM&Qw47q~MAwW)%2C(66S zLd85ydMWo)9d_L;dpUw5?nqhe6Y<1c*Su-ZMq}nid2>^9ym~G6Z#z3=7M-Gf^!SEy zV3uf5v6h#AUz z4Z7@c7LQD4y72G~n#*Q1cbMpNHOT%53t3_gRtAF!-W294n`*o^X-!a>zfD!a;(QnG z!k8%33T&ld%~~R&N365}t3=7p0V{S0wV;ctYc@5|;>S1vObO0AC0^8o=MY-TQ6XX; zaR*8dk|bjNebj>DGW)_YEiFc6bp2oX%E}b4uB1#QYd2Hr<2)K2 zItveVa6dV}1QqYJbCp5mLs}r|v;q28N222IR&w)13!*9JCi3$&DAt(Z>U-lJ^J-MR zLmd5@z%2|`J$9_+x*cCa>83n8t7q1BH6}riZq^@2a@4RVL=I>N=>ZQ~Ob>Xl3_)5k zf-Ff7&Nc1QgwU=bMqhuehNv8cd{cBFT>&o9$*0Fr(%cjrQllpL(UMH!&;**hNjk$G zQFn^Q8gz}QCf(Dld*(LjHda8ezg`X$wW>+;{!HW!lY?-te{zyd@Ro9jH5$|f-e@IX z3iDbK>Prl+5(ZSJB9~BC*5GR)?+79r;MYtFjWHf^uECj1MBP>hP;57>NT@S2JvRJOuk68X935c6pA-_`nXIPy%^@8Cb-+tpc4hgny9`K1fa-4D=uN90NuC~7sVF<1eL^6=POzl zbhs4+cTp+_ux(DWh3nSJfe zg+j)3T5u&*u$}v|9L|hblYHn-w3*M~ay(KweK4j8q9MuaZwCyIyK^^6uYCOyYRttPBsbki|`^`D(qwA|8fYE_PpF zUChJOf>psXnu;=(_hb6rZ%dTv5ZDhYLA3_GrX^wLQ% zny${_pC~w_iCH}^+(>zmtIt=_ICoFvHDWDMFRWG*335<0{%OkY$mzt~2ZrUQ)iUgW`7m~pD5JW4Y zu{kB=W4&tF+MKqr0Euz+LZ^wyJ*yZ;Pa;lR0sBVTUX%YSqMze%7Vf%TJ^CtGVy~9G zp}J75=UXMY2S86e0CYf$zdQWznUn6NzU3&B{a9j^CDnPO^(@qAspJB+jTyFRc&t7@$MR-}qI zf?}epH%o;}{9N-~&CF#dCZ1yO;f?UrnwFc&N2|?coL@`MXUV6~u7Ui`dW=9!NwPH@&T87gi=Yy-V+5K3| zVbTX>vwaIZem&Y1lS^H~^AjpAO!J3NNUDoWU-wY))(kwaq!Zxg=*Yc)cBZZ6(yD>K zJ@m&jGz(!9KtR({P%zP^aoZxB)a!GosV&Dex5-v5XZSrXosiePVCIeFIc0%y`1^(9 zXTb?BoF_G3*>h(0Sp!gb0nbgqp)2Vu*(X2AGmJHYeLWEK25HwKqDgMwtksyPE~iu| z5(k3tBPmfQ^U8WkW=v_alZlPDFY@})YC&gB>u0X(0ubPZqX~U1qDBr7NAETA22gSZ z&hMRYXSkHVu$>V)W{7%Ov_%`nTt}8QoHF6DVf+#@XSqcU7~QkdbQ7EY1v|PyK_HgB zVI0fJ`mZJ6GD@@fDBxBRa7493B%w1;@$uHy?_r|;ZYA9Bo^k~uF2ubw-k(LrVdL*= zjrR{A=d|f<#k98f5^}-^bfJ86ysH{`y-=Ca_jbLbr7OB(;Uy?kJm^=k7Jr8;d6ZNx zCQBLwNq;Kj0hTsY%q!}MtRLq)%XxVLBgbSlYB1DP+X!VyYmHeAiUMwg$M|}ww$;D5 zdSMHccap!hr?b%{W6I4&V| zlbUJS(zV&!>}k`KMG5oV(<{y}=o_k9AOkl*AUD*C$%fo_o)=n_4Rh`;t-={11Q%q8$VNnod20sgENk2+$(3sVeyYtQ+x(u{CZ^ZLN6j3X#0IVGfH|#O6K9#>T4JE`j@IrsET4Tt zo}#8|I=`gK+CTT~j;wmFxH&f(Yp~Z|?Bg9@;z`|M-Ms!@YvmQO)?@W3&iN)scLPF$ zxWStb)Pv2G;N3_mV}N&eT)ErktgR&L1RmkUP)85(TT}AnIwy}((cJ=`JAQs65h74b z@X%f^5~yMJ^+>h&YqTj1xsZbdQD4$~#})|K^~c zLVDL%FoVkM{q!7C`>K!yfLW$29lBsMCw@M#SF3KRt7Ufu*U~v{907xrr(C z&#RjZ;PFZizen%|h$k(5Q4-q=*y!rsu3)j;iR}$ee9?pQoSs;L4nG8nzC2PLHxss` zKyyKuWm^e0gK5FWghq{a0d_<3DEq#w>?7=Opu`}JL(dqle1)@Pd@bXJxpH%CLZ*H} zN$H#e{KFKEXv53e@mah;EixVE=qHNV5jHbBR?>Ck46W5NcGvj48b@e){r8@A%JBR< zR5)VZT;tAUnzc`}xtKo8ys*%-jsaiVgKS7YHj|S{r>mxl7dlVRBx2^-L`C%ds`iz! zV)fa_tIGMX@CioSNfD%bolCJ6nWMOMx`hlt`wX=Hm0>okRh#r$ea<$dsyZo$u+c6# zdQRT`Dx7n=1a|u?Y-j8mL=nedr5^}TY1SWxH^O1*?IKqJb_k}6UM64t@hc9s$8TPW zH-B>8bi|vJuVmD+NL~?a?N^%YA21(OIwl91sJomh4aI8-UNACcHwb?-_xQuJ$#7`~rend$CG zm#A#H3%CogcKAy(gKoZyV1QMk8ZH8XI-fxDH|vOZiVOniyO;m;jT{yp-9Y5*^7m{A zQ=^Mf;|`qxZTNy_5iN+zi=r`>2sDj`9kZ^|)IU;832iYK)nLx;M{XO_+ZDvyaevsE z+h7iqC{8!=qHPg4kd02CC)rg75;>i3A7>x>L%hN`--fM&0-|U&e}F-Hu<@a-F+I4- zy0g(lN4kS&o$i^Y`=C)LmS1-82)G%1grY~2z&met$l)0!#dvhxsJFBE*o1+NUZ4!a zl1#lpF@w*ojW4IC?PK_s21D;Ooy!HhogMVM**hyKVhsDs5si;liK^bt+`3Gaii@T`8*hmAkEsw^VPu$Z5=PF5aNLM?)+Ng=YP3VwH>pcUDR| zqD)+`H=0j(pY1(=@yE__x0js&%Y~Kx^8Md)D!u&X+wZ>r6I5Ddb|5ZaM1(D#2CWt@ z)DJ1R1ffH*wO4undlp+_V9cee%W)TjFqih;at6mCsL*wycP7{CpJh;`6^RSG+5@}t zNPS!lAzR6*`>>?jxd3ar9pp+(bt~!4q7U__T|RBB%$d2M1>n!k zoTRYfe&2HGH~kO5nSVZ{$CNn4f3m;d%go+It(VUIz5=!7EbINyx*Hb1?eQ?{)_5;b^AFDbIC(bF!u^PPr=y z=x20W7JFi?5r~GYa~@@c%ky#S78>bu_u)XwuhA4&k@b%xbar+q(7*|Lgig0l2AvO6 zmQ*`C<~Kp@kEZ+kAi|SRiTw@g%=NL(%Rn`*`@PvIDmMXzhPlbw7$L{GF74xNOlUUV zeN~YYaBb+;TOW3Yck8kQc2|}ld|?6(bRp5V6FDbGWye8D=$uiI#5N-W<#}AF72pjl zIhwl7Z$pvbuq1*6J_;LW!y@fBL6t5vD>8wcBSab}{IbBJctTIfs6qKnaHG%$#b}0z zwor}DwWKjW@Or407;Q52JbRVt@sLb}pFU|*WXm;I>k~06_>)9uKTM5T8Usht6Sn;z z#F_@UufNoU)Q^~ixqlxjcU?y z7ndc*l&!j+FKiH5URZ6dDHnUtUwG;TT_stPsGN*)gzW%ZpBFBS>%73gvl=H%3>z}T zx$li3LXsV)KJk#7XO8&j0!SCjwNv-|N_5r_JC@z}{RJlHY^X;a_s5nsb8^@AnI5hb zh5lfQ#yk}1W!@Z!89*%uMr@${T>EE<=}|0kLo=u&fBg#ZYJ8K@BvE_4@y)j1Pa%`( zeTV$s+L-O6vc1Ue`k)8X`N;0m`8TALXrdD*IN9NA8#OB zdR|#yf-;|vC>pfV&*4vOYf(7Fy08v_pBupBy54mLpZ~0Wfm5=U?G78x05jnrKD*DJH}{gp(`V1?yZGN;Qg7Cu zKd=9vr2a5nEdE@=j%Na>j58SOf^tyoks28h7Ad*r}k` zfAaRn*U2}7QTGfcPJfuZ>K{)){BA$t8qt?n{bZ75$#irwyY5V~{p4nJnRGjtrl8kH zjyk>s;R0H0XV}|;y~g>d*FRCov(UMu$RNRG4Q za+;l74yptVN+Dei2e%V#Vu=*ge`v4lc zIOz;$H_#IT@z?Kv{`N0W=jAs)y!zqoe`6x9KmG9b_4jYyB!Bwx=j3Jb)61XV{_ySJ zUcLM|`RQ*z|McUV@3)iWO@@eN1Yt4VPiP2%w7qQB=?|ug7XJ-{4qK4RL66g?O|ov* zzXBXPr2Lc~SKb2A?G5a99!n<44=12E&OopO_J^ml*?50v=lc43`@`^Zdo=m5Ghler zotDDzTR>yd|8P1>n)Sx>8vOZV@-`b}A10mi7=>eWwAHg}%%LM_8`x<$oep+j zX9zj~7I`8UD_m{8mHp@J1QdYT8%7xxKl5XM-+WEAN;G?e6x>LTs>0C3hipdIKeXF{s;}GThc39(sfPaY z2GcF4Gw|~{oi#o^5co>lnCpe#VioS38cIc@+UEW3U%vnLKk)L1FiDxlt@%J^eIBEp zq7WXV8IgV=Z0*i2?NfI-8UMIq$Mts?{LAmlf~D0PK$N)`ph zc4OQZiWYOnvNImz>0~Im!yZsig&acpc~C?*+0OLx*dx`+WOVM`6fKxxA9H6|a0sD@ ziSSj-nY-fQ)VQ^;iLAvKMsOp5`3MSpBswn13C4!|(+Z)Z=m5E*Laj|}Vp-FZX?8jp zU4!m4{4hKHYkzv)nRQRC+fpQY4lXHTDY467WRa0C#aa_^#d7^6tJ77-IlIgW^OJ)p zR4ztn1zV4qLC4dGfdz=c7BFQ}S)u`VDg&hUBs+;Tk@B1E{k1qJpA!qFeb zN&1I+b6$b!;)j8L^oO1Xj9;lIM}HVx{@>wxRncRU|3MON;vYd9LrzN=eNH#M)hAcx z-2t<{BG=ZDg`}5L+v%et4O||+31T~eXhe{aT7BN&AR}V1#AR&_RUb-0m!d&K;IWPn zfcN`OpmJ%A*9$b}1y*_RzPZ@od1X~G zGJYEvA1rwfL-ZE8l!SP_{5a{RXQOw6_c6@*g~S~(;%5^3J6~(WmX9?VAweu<e|* zl)S^+B@szZH-4!5Y`PrzFxZv!;d5Vo88%lsIl?6Db z&lc4?(RsNLJcTKus8K+O7cn}#2*{uYDF+!*{@7fG_HpBA7^>2dTK%B0-90@u9e(!G z%xlyfNgiROA{JKIg)4$Z)d@Cs>=EeL=_}03XarI-mcC>AxmM{UMm21XXRSQ;23i#C-EMgJ7IZP`}R2Jve z(JPkZN|$b4^ZAVji+v@qN9AK7h~ZX$QciP``SP?*fR3#;j)v3>7HR|m&GQz1e*P)0 zHN=Oa7?hmk0ifud#x9FFU24+Ey1`tg%HG`dU~%PcX9zo?t9S&KvG$}Z*sLgQyXWIJ zE`-J;=V2Sa*gGFh+A0ea190zLquq+`eAt*v8m1fmNzL?FK@4+#;Bg>l2A6vSsVf^I zP$o<#jyLr50E|6+|gu3L?t6as!hMI{Jhil4{b8NfXYBZ8rpC_8>OH#tEjIyFhBWF9N-q z9TKz2gd7Xsy?l@DACcQ3B7zUG14p5kB6f>jU-3(VgclRw`;~dn%esN?nBx)fLN+;kp~aUREfs&;9i!%M?$CTwerPD#T}_2-SZRRb0!c^`LSZX+5M2os zp{S8V2;maQw707X(RP>W-|DYk;bQ&jmApKr$ZnGX2spQL9ogH(b;Q06R+9E0kK*61 zFd1$`THltS_3cB@8oGMx&{|2J7YCB^d%HOtd_VU5?q8EV`H1vfE|8W!<*D=i?@F#} zcjknV`8qUSc)2Em>H{({1f!;n@$WiCK3S?L{6CA%a&H zDYD~g3(5I7Co1K%!Kw>so;G#4X3=3!RZSH85ydu>Y3Dp^Uyhg4fB-d8Ycz^h zwE<+*n`ZE);Tlm)kupa@=VLrmYaHPL5dNR&GarBwKJ1EPAgBfU5dYiYf3@jo+Ej0v z>P<6xAQU&UH`qWE$uYADO{hSR>9aj@S!xJ#1&-OR&UB$)<+sx;YNzS7)AZYEns%C| z9myu+$*7CYd_5EPDzcr~HS&-8{YfgE0-xOd8+5Y5Xg+NMF1O}dvEn1O8Klmx0KDk{ zZ(86@0i4V^g#Ito5FM-iR#%CDo;HO?7ailf(}F*n<|$CiQZ9e3K?OuKd7vO^+qS+k zfkh6v`^r4wBwFS7;*fz#$_E0MgDG+WEq|J%o=}hz;bXakYuagIe03Jq*_gq-S!Zf(JhkpT!8r-0JMJQZRr`A0Pulrl+&>v1e()oiIx&-xFv93Rev^q$iQv z!$>o?&Ka0obNH+~aw3RQ9Pcl};zLW8$^#{Y@60?!gE9!OZOAUUxI>9TsX(qQ4a}fVO((lIvKkR5n&0WgoL%^!uCy! zZjNJ@J)a(1H*tkgzR!gn1cjiVpDS`I>q#4NI=iG`i9w5>*NRT%pt2Mii%{Ux^_=XZ zfIy^y<1l+rd0*F61n-(#HWDwV!231ya&@Dc*!NqB*S>$?=1A61jIs#jUZ+v8=0=8V z=S!t{0w5$Ft&<$eP-)lf&eT_vXAjaQ9Q)zI}j>m1oh=MJk6C9W}-Q5%rC7=W8J@mo$3|5Gjj-Ld_)yCkDA>+8?UKx*pt_!2$GY+A zi4-{78v+ZLWa$=$gJk{LRTm@UW9&ny7%6)L;Ph0F`H38AfY3}f>Fbs{kWHWBnpzQq zjp{o-)2y9GG>>3Q66?;WX=_I5cJP((zG~ZGlnccXPV`k|5!TBWL^K0+4jFZki()RR z;4{AMpfJ;15a`Bx&^9U5BmhfQ;}>s(33kuN0~t3kH+v+$l+8`_74OM`9c+4d=%OMV znkQlk+N3cF#f;?d|92+y8|7p{L7by*aIh#$M%V0L#meH8dgm+!olXuR?VO>H4O z-mL9fuzvpXoQm}LQ(_H3_;KX2M$kvimdND_VxYF562 zhMo5+UnAWm0GV1zjjp9{4#H5#+?|3japqHvXr#VoUugWzF>oS4K$}642kwl z*;_eQpy+$49E3zUC#onfDU(AOh1o{tm9-4Qfok^mPdl&{1Hy;;!JEIl1pLrCNcYgG zzPbxejr$L&VPUMuyA((|J`y>bynEU-IT04(!Bt8&jz+_64Exc>;)=*08N^*R0f2e; zGWkOPH=5(WhXJ2_yfelFKmMGV8utuM7sh|1sW;hyCouJU+o$)BF;*P^t^T}O58}Vo zclRFSzkP|%WBj+r_-~K#-xkGx8&5hP&O6Cy*v+1Z;BH~Kx4sGi(vtBxK$K!+4xDQE zA2j~v$G`pj?e{Pmuf9)y{{H26-~Y_7c5vf4x$Mr8Kfzr5E}M2IVzb7(QJkd++icMK zcwEx!)3)7IOJ$Yz306=}s9ad@=X+W1E?~iy@&4I zn@RW8s7o?KD2s;9o5@KJ|2I{-^-4ND;jA;7K8@TvwE)XDi5N2x+crd3s1w2J@AhT(tPGI3KcJL$6)7#S2x z8Z1vLC}tQ5hCo#|9F2wAxQhcS6%{rR+aI!FJ42NzGQ1J4bRR;+Hbyf>qwjhYJcyPo z^{WsM%U;JY>5{{lDqc<25z=}kAW0i!_YmW^JxC)8SgajU>%OhfE8WIQQ%>;iM#6F2 z^t2=Wmyo&YPiB`OV1A=VDY^^*({(NfJVxs6Lgr$d)=Fqn!y5_pSD^S4D$0!KzQ9)s zjBAYl;m>^`sw{{!LXkFAcX?GyPI{Gc37DZ;kn(FiLyN#~7J?7q@rF({D6H=A6AgE5 z(^b2(|4p=CNkFUwl`V)xliouu+8mskS_uR>d%Jr+3u>HI~wNnbSI5 z%VN5f4BgeEVBwGk3_ImN0=dm{p$!?482g|d|7(QO|EK)q+J6SwJe%A<_CJ1#?LUpZ zXS?;l{`36N{_{mXkM^HO`_H5Or*!;(mWoaQ{^`y6taCib+*ANlZ3hzB0XT#00@Ki| z@Bi*tgY0_y3fey3-$xYA+X#YGA=2-9b9+JqKTx0heq&x@w%#UflKBT8PRX8fHUxhoGS7n@a`!+9j;=xN z!~r9YM;pWX9qY;*{1^L%m-Jifjs|TrhdTG+9X>D|;75&~jq`?5K=~+!HTmE5yBGn; zCP+aE{EpjZq66u)qp<$J>)Z&D@vHT(0y1hP-DU6D*b+f+dziBvU398r>QnYx+U>(5 zo3NRZ0^k$M+pJICr!(I9c<38f7kxc$lM7-NO*7^;fD568ffa<4jDo(E;N?4Ld}AZg zK-isRI)lvu{hkY;=pv=AG%!HznQ*rR#_H4>!&-`x#>Hl;VokC~M9jfOZ|=9YrY0_B zo=?RZ;2C(@7<6<=azjI(7TNS6dAE>bPmBF$7J<)-d%9Xv4H@bCzRgQVd3;vrEj%JTWZPxA%G|J^56f%ZqC7`tM16m>W%# zBwj$h_mDv87Z!)dTpXt%%g94Y%~`{*`)c}g5%xFg`(jm0BpXwRz_CCNW+=Vm`H80j zEO-qy?w&~T67O9O71!Agw5lkvqs3Nzk!e2_FyFibnfTtl6H8)fW?Lkq4u# zh|ifR+R9EqIJcQQ7+)Q^OmE!{pAmA1*kpg7{z;|H2XKIOULC*mhy9srbL({RmN!`z zJZp6}8nnCTGw&&;`r*fFx~Pw1&l-%TS)}g8ByKN0HBj+R=XB|IMuboiV zhZbcUdcX@uGt;woqS$*Bi@GV-c8V4moMEZrfvRB!4iKqd!;|(1*xE2f__{l&3Vx^< zit&oD@9=~}uNHY;>ZPGRe|}P`Lr5?S)9n@s9+&|d5Zcs)nnRW*HIGamh;MLfbAuuA zs>##VM$(x~T*ijdmt&;@OgQZ|eQD?~P5i=FJgxDUJ)B54!1^l3MwMly$%I|!JlK&8 z*jP#Dz)ni|rS`Gp5WTV}2|8CtEg=M9dZ8OR@cGREYm(zBp-8__y)dAg2DA&i5yDO^ zq4>qtme;HXpi~TQ(l+-V7g?tl36jj4F|onU<}lJTVoCT)f?8TIjhT@b7|w~p1@q01 zD1^32_@_`GmPVNbKfb3@kV)@N7&Y3t!=|u9TPWBsxUx6r)4c@seA{a3cY0aV zd~cGd5F#6z9Q@k!*oxR~Sb_S&kB;{iM~OW^w`JApFDiEjS!a?)B{Y`>A&lAtm*$0B zmBj6&vqhmYa^25@4X120vWRGqceL{AyC|4pFHz2=ip|!rvOPXm9WbrM0|b`bE1>!al~L-oAj_PmJ4gsVM*Je0oXw&&}!(I`1bE9x+tqF`0snXU^kX2Tnu`Yflc z+rDYCC3)C9^?cfM24STkz|_;j9@@-7h)V-o{>_K-&HKDxqA@WJ%S&NxBX9*OzLkqH zHq2$raiQ4_Puo`WOS=_&ZRdZ#l4AP;Tj?^=TU+WV)5v>l;LtQ+PeIX$g70AMzvxOc zg#ln0FjmkK{z4;#xwc^P;a#vAVcz@SWHvg>hEZChw8w;8+NPCT#+eU10N#G}qeDN= z9{>>U-0hac(=6F+RW!QG|IgmLx3_WQio@sce2TGpPAu87Bgwh6cI-S!Htps)X__Z- zcH1}2sRYy>2c84aSOnM@##N&2I@N`x$0k-X0=v^5wMLN+Z1TDF!t$k%H9} zyVDUu5zu0oQ!@cb`&rB(dG6qio;%(u-`O>cv^&lPYAULhmDE%P%@(*e#gQIGAL4lG zXu(ziwmVGQdO^|rJA_NGc)>9S$v}SsF&cjb&xYdo4|A+_TI#0r1F}@-PK@<6>zt(vm67>)90QdHF1gKVoI`E^or`)=2T9KHou;csLlGCM z2M(}oP5e;wPWugx>ct?OnIv}8K&?|LP5X-Qi@@pwX$6}NQN<+X$Q?RH)OwjpuOksq z{ty}jM;uu~H5>=;v*Uf#J`6wG+trQrem+kAm{TO~L++3OIKgYP+x04K^~K!YFP`iZQDOR5{|3axCp#B-A$a!@T??g zIL#VSk-S%<292w@K1SgdCf3gAY-!tJGlzRhm^eJYP>6!^GDQ_NviT9G(>+hNqL^W2 z%a^uRoCT%i(R7v^BL>r{kfgN4(fO&j>7VMu3+{6A5fIxh7UI~ccU-AJwh}2FK|7ri zEu8g_-YzYl6z&rG_O=USMhm5T8n%W?$xgWOtID={l^GeT!>PANkK>pv8*QECNip_@;30swN^@|TD*a)mk^v$+_R#NDyuKSSI)h!xl zbo{X;s3WjFz^JQ_@yJ2$Zwe>2HPTx-Wz;uUZ(ZXYh00F0y&Z@LW5`6J(Z`X;5c&+- zugpG0z%F=_>NQ79WR`Klv<{FP26Ua(Ho}aYE1QT*9U*$5wMV^_rDCDHQ$6;jb!jEn zyHi0CoMuN02(zYn=AEv|a~~$ASMG2$Ip~eLi;5GPydUD5^QOII#%>)9X;1S7sFS_^ zhj2x2JoXgVpbtzu=%R}bI~R~s485yU9WqZtIkoPmN~v~vg!1E! zdWWbbZxvVa#wTCTROJ0m*HYANlnlAlGI0rP!25A`9G__WWHHxjrWHu4wr-}8yg~Hr z_&?qt`v2J9!u&ti5COKp{@dDmkjwvbx3%@v{`)2VzS@7k+JC>=e=Em-36t;T6Z|Zj zn8wdF<0P5oIHEeg!NidK4Yue=K_E;8%x2xeWXPPaMrOCXyl(jeucTo(Vs*%mN0 z13EmAKc|J!A&VisW$xc~`U$V+fP-wwcmJVe7kEl;T6o0eRcZ!+VgPQS5fx7g#QOqw zB8yQmxb*-yytl$)>jPKmNeTe&76pt(wav{}E^Zf8oCRk~-*I|nd~WDlyG418 zx5**gMSt~Qt3?hcCZ6l+$%F`D__9eNWs=G}2PSEW__>~JQgX^m49GiF7t%7o8z>OU z_^C^|)YETO>p4m~f@qRnQkXkQkN8Ltzb+!Cb-=GI$~lJ+cZ}Lt&_61_8SJHux`KV_ zW%KUbV(U#ZOzTikTWCynG#Mr(69rL{Hkv>54W0j6?6{?mW*nb!!+#FaCdrUlD^`Sq zl<)Yeg)t@ZQKD2?xK+5E2i;`svEZSux11Ood0srIbT#%GLh0paQXfZ7Cgkrl`1N%o zGuGF|eSzA8O(&|6Hwv1y)}xYk2`11ww#r>ojq4jzAwO85 zY&+H^4k)lfRFep?aK$kLD$(5xkw}KGW?H?5J8_gKuu>(QP7IxZ^)YzZ*A&E^SuWL8 zv2~pq8dyaYW_A$^khaz1lQ6{v4NdRzo_o2_X_!MBdyen6lSM0BaedwNgOxU~TN`b2 z2n^~ZA+?s!<>qQOT8Ct8eh3?r!uE+l@>rTdfUPTREF#qUIfEiy;*}C@A{Hm^5QIA9 z-4em`h!a{_y+z#WaXO^G0+bbIgbn)A>QlT;ia>C)bg_?a4@V2dvgju1WkOVH-c+@`@olN%S{;$} z5?Z9v9I3>5E@hjqQ2Z6WGjINHLH?&}$o{=B|M&f^EieC5`@y}f2Vd=fU*hkp{qL*& z@2maq`usm1QlPp_`*a)weVix#ROJm{A`ujyd*@PbEb?a@Pa;*AYo`%T1MTCej@LPc zg0^_Cj3MYW*VKuc;0ILY=p;Pi6wano{Y~Z5 z2zXEi&g#jtQ>5Hb!5=v%M@r*dmOXy z&+a1+L6c22kgVid&@@y4)sDhtt_DtKYf+g`{M;vgmK2>sg>NhjJH*g-LWKl{+!Azl z9>sMfExD99|W^I$=iV89GTS0f& zf;?{03znP_s0lZn3BU*OSyV*gj&|qU_h$Mz2{s~=bwuYE;i%#r zEhG9Mts)Um$CF(K!?7$d-?!kqNTLEy?lwi{kqEDByl~yUbobc%bYY_73VC;|_d-$r z9c1L4CbaeEW-XkHhf3_!Z0?<4Y91_gzTtteNm%gp#zn0#HxIu5wN?}6Y&FSkG@J97 z@=OF%9?M`mrwYgJS&>{)f752j;%TxlS%;BLQf9LooaM%FI%JhP2W`ieQ~U3w=caah zRZ*AJM%Zc7Z5qQfMd~2h{koZiBy<@qx_lF&cFtYbi5XoUw5*mCZ zhmWdm4#Wk znd%=3vlGW)F=iZZ zvEW*{E*8g|5Xkj)N0vvvVBDO}(<44tg*uy@J(BN5(@m5GtXKglnsG@%Rme~CT%T+c zL|TnOsepx;>edW_Ob$jN?~Ugo$B^3Rd?dU%OlF*@Jb;Ia<(iBJxb|=o=p2AFhP|bl zX_V2OSwmIY6tPc{Ti-vI)+-(!4x8p^(c{oEU+RNib39~fr6pUs?l#lfQ)S?WLrgDgs!aI!ib{K(L1j=rWJq5{dfc(7HfF1zx zXuLNWejeE5Zk+LVk$2E#Ot98j*m?qJ$l4>q;M*bC7PXXdZUxxS^7vw zW6eImO(LK-x2CwrI(emBw08UoirHKm%HBHlT{N)3#>OH!Bc{p4ttI2!q#|a8rCugo zOeillN4ZfFMiq3fDd^uD;myq)gbqRQ)Ykx@KnYKB8$64*}_j+Naa=yQp2@HgBp#qxSAL+I*>OkvFVgQO- zLvD^wbYO0)DJWr9!plZ4UN7;AR$5g$IKUP&ffV;EFe254!aUG|<6&ss^%qK`X;^&{ zcX@SDwHd8(Lq=e=p_#^)Q*_?7p>+$9MYiXp~}mUX&7g@1lL-rjx+_1<7Tam6?+8`;?_&_Of2k4d?O?7w*8X6Z4R_TWv?1?eWC68f8~ z4VY{cwz6sPNOz-c4*wM>6JS`c2BDvBQrrppE?5*q_Av)A`3b@FDne2zbtiG}gZAer zY86>;$yT9wub*ADZSrl$ZllXT-{rBp8%Zpj({XWm7rj~*69#rnd92Pamce`x0k7JH3WQ$J3*MO#jBFC3 zalZ2Hh)lbo`NpPU)n#a0aDRBFU83d6lb@0CxX2K&5H~apLh0G$*dX;}o{Y$mt$z?g z3pBQPGzcO=Z#)@bhG$LH+f`9G^mAiRNGr5#9&GleQ%u!w7PKznDN=qim;wr4wmS>S zOuI|!9$jHL8U>>Ia#u$>Ex{KYz!Eh|ZqQVGy7(x+God{xdMP+MQyi9Xp>=aiU za$PIm@=*2XSr@lS{4h+Lg=pO9c$Ff$P*=JF(jm1MF-M1kX0!l*XGWlWP-#V#YAd>v zY7w$PJ*lEx{ktZXf>ff270bw~%B4*rgRsIYc*UiwXq~j$TCnlrc9+@|6t!+OXYFsbv)dZhlS`fvvRM zEDbemNC*NImDYTQ@z5;TGC4>r+^6|nFWa$+ve0y)q`fQxOSD~Ln7MT8cCWyo8Wpy# zP|U#v(13rJvJk2AMK&UMMHtS;J-MCH)qGQtIApDWYX;0VQ-aPWsu z3}*?!o^(~J=ln`meMJ%W0nLzwQ1$wVM0%1OYMxXcFqdc%#bmf4E0~L+hp@)F4tnSG z{31+57lIr{2N_om79&J&JU%Nza?LvE7_OT3U>PiyvB*`k3fOpkfG+G5la09UpsC>i z#=wLaG>K3sGY`!KR&TiQ<}iV|!YTYhGR0MO1_SPOT2a$$2cCH`u`UHpgJQo8v*#@M zM&Gxq$Z_fo*jecSYI2>Td$5%jXI9apF!^*o%FtwhnX@o}w;8q2>FPsN{}j(AfLfb= zdiofs)&DnXwc*hUlZlcK)Zw^Jms_+k2-CH)*o!7Ib*B{O7<@cCO!xGBnU8VCl&zjv z{5IC>%?^vqUxCFz0rpQZ5C{NMJ6U|Uu@^9r=pl9U(@pWHjdJdlCa&``o7Nuc6sr3# zo@`+4y;^XdF?bp_=V%Wao)+(?c7k9+5H4eIOS{31r$Ch;b1_d8av8NjTCzt10`g#> zcB%g0f>>1D;ke*PG8nA4rb>mnisZ;=ObnlhSfviZ>5S!nqn*^Rn!bfbEkS^D{rha#o^* zX;ii=DCnPe0a0$3VKwe$w;Ma^Y8iDg5T%n_Is+-l(%TVdQbhvlTp^e>RfuVu;FLTj zpi=kg1Qw$HlDqE8C#~MCui-K~JvnR_n6Dni^@L(9MebNhgub9QM=+ot1Bt4N_sdws-8~gjE5DCF)$eIz4WH zQw0$~m*Oe*mn6pZ$(cfis4i!2fF#!>v#OB;C%#-IiYERQCGQuLULnr@a>Dpp$6{e$ zZfH!dwtC?1tnlRVuSEUwp4=quJw^K}YPO^K1rFk`G$7oUgXDR~RyQs&Iv zr8|*V6fQk(6}%*TjluPkxE4WIg-TZ)`BI`?f*;^H8BOT#swDITt&IvY;&u_4J<=|U zE3z~l9dy;oQ5b3zpm9lfQP5$kB(O*ifkI@{7^#aj&1EBt0+}SBxj@))D599U48W@=O?C%6u!}}cLANWvge>XIf;(b!vI`BqrZk20kT*Q;!)N!$=4Z) z-buIk?ePai(xUf3Fsv?U1B~h8LDxUnB9u|C?*A^top?EyZpnY|{U-l%-~VuN5jTl= zpdI!v57>HxEtD26YilykT{7Wb0h;QBIKEX|KnT*nfg;kRmBA_R^JO6Fqo|-8q@5DJ zFQ$JJvlV!5rZlhVT((Q_)zQgI(o z=*omro#A_&MiHrr!l&lyE-TiJbZIBdFhJ#vN%+>BnR_|M%YtU)DI(Ak^tKpnj8ubZ zm36=8GR7?lB-IU2uyr#8L~L)6e$(kDiq{&7?^>gPkVLVpyH6rslkqKH;`5gwBVzjn z$XIVkBI-GNGT6^iO8C|Nj5V-OT|DgmjIJ6#*YQ&;$ycZD&zpsbZ!Y7K_w(kLac}#1 zGav4+Tl^BfSGIjWgGd!DuHEZOpd&(OuhH4==gmM`iJNk>6TPvmmU=H<-o>-1;S!(8 z%LZPT%@~G977~xXmyWb9YA)20mLnCyj?2V|7t_3K$Z-*9UE4yweDrZi8*{IbYw}O@ zx}oD*7qzk=?s#z{Ij`7jaY+pIM#jl{35Tl1SQfP*YC~an5?)`tW#POmh&v2~9bP>O zvKkUP9?ai*dy&!C8ZcPM0JasDChcaV!`-e?UHdr~PjFKzn{G*jRTb&Kr0Ql}{IFWx z6E;1$TAjMI7qRWq3dFWl`i&|!+EVT1yI0fY+Sew|b&5pe#671tld`+vo7cMj z$kAk5NPX-F=3nbtWCHPvTD$H=+|n`6xnnmn_Ila3{>?Xhcg7h1S#7M|Fe@9b&AKmp znZwPPuQ$xhpvfwJ#xfo|)8$f7q7LNSAU5bv=79Am?hP=04MVQubgQF_UN8Ia@s&s? z&Jf+qzEL%Xr_Y-G0&?!8fvjXpjBj+;QGin=gsyE41pwj6a)>rNi;$mr$impp=$bU( zD_9QWS<>&0lH(*xAL1j#_Ws>HOxu52zo8YT{>{Uio}zLR{;_xt{^74E)u!LqsrPm2 z{pF_K?iZSS`}652b}XwV+}Kg-d{ZmeQxnpOaAu>cnxC%ibqO2k&h_!H+$mgIy>H#v z2t1vP2bUNCs&;eq_Z&sW(dW;LEY;T~VYsn6%vGMMg(k-9v&G%efk~amR?KAhAAJ0L zW3xJZ>?$~IF{AA(Ul0U=Iwn5J6WL ze1W|Gg%ET5ZcKDYB+`4@`Q zAiVs!aC+n0FEPDung_3Uz|j-;rUu+<{_37Kvy=F-cXkj5HWAD19SBO@-!xp)Zs9-8 zfS|5#tG63ET}tS%@FtI3c+hG$uG|+g4*@4E9`5gLZ!gXgk3`2v8qZONbLi}0=0Bgr zy}`%cxKC7ecW2J-(BA61l9j;_g`Glf+MUHctiUWx$07>o zjpBHc9VO$#T45i8H8C)#_WK;#uKDx~>`u9o2o<^zSsX!mdptfPByPgp_q2_7^xllv z_!lBlvzu&33y}TFy722M1#9YV-(a7e%P4QA=YV}tzeT6@*V6S8D6>DwQDHyAq@>l> zN`jDED|P++N_p*Ebu%YidKjT2DJ9y|J+dN8-B4hbN_j~EstYoB^+s%dd6dlk3psDs zYvsVze~~3lGRe()-v5gQo$0Vmh0Ib;UK5eGyCI7%bkWB`H}9hVMR@n;YCL+Qy!rFL ziz$EpV%+$1RW{6tU-YizZyh6vpYbi}MW-P9?PwGaGc(`zI}u%~Z5~|uyu#K0y%TeK zXd5!xDqv{PF%Q3t)LRPQqU-A<`bFm>)M)*JO8Uticiv#uD8wp)e>;(WzY@5^n$ zoC!hgFqRMT4Ltke$~mdnNFAkOTW+bOVK1f06TwwGf^{pa@}UsZ|N8p(ANH3`#-rq5 zBc1i{^k-+&Y;q?X!T%5XoBiqZn%V%(;{M&c5q>_ne~&&}9sUhp?mf7B?|#(Yy7!=U z7yo}hYPI2W>%XGbHML**2m96D3{aWIFl|f9L9yYm?g4NQEx|6S{elj7HHx z9L>{sI3G0$3Y3oi`F#KHKfT?L9>4r0`sd@)<_ zHtUVEGr*oe{P^tk)4xNV$4{QWc)tG&cH;Zz`!Aopc@usA)9dJQ^y=~J{pU~LzIgmP zdiD18tDoLH+l-<&F(Ss4EG9JG?gs+}v>e2Ek8Y|u{|gLn3h0dn5h_2JUMfyL0&+bH zDy%w!bY_Mf^{5H>Js(EnN!E-~!1LizmQAVBdqKJCX-evU{Xg1p8ZP4J*1jSd0zXbP;Cq{JKqFPlW8Wc)!@0qq6) zG@Z;SPayXXC(LYeIO`pAAF$+4u!O#O^8%_K%zCr4&B&1J7!72TgZOL#Wsr4xBT6C! z_~Stj3;{ln97_mco}*|&Yz-_n)@^Sh?Qs6735Juq4y(1o5wIpmf+|$FcZLDH@p!;x z%xfeBO$a@86bcG#GctUPU~t;OxIsrp$zcy?0#qMNKr$G#;1`xSfr)EgHZcbg2;vZa zbdhU(jJcvHeV9bX0u|LmH3=kDM^Y+*hFwVYR8>PsJc1*TPBc)MxA-rm z0snj#?L$H0gEwa>G?+#&Uc9=scIVbN$+$n7!%#i^2tzrU?TIIx2t+2QlZo>LRONV<`GsH( z$VZ^^f=t~!+Ph^R*7}p<^1shcsHHa@-GjP!=&&f)TEd46)am#k`eFG1?9Phs)u z1s)&9;|$x3}S+gUKkR z;Li^yU04Wa_0{!Nz3+9OZxlRVD|o(L@O-D>dA;Cyqu}{@!SjoP=kE%hzb|;cTkyPF z@cdE1^UZ?ie-=Fd*J=ar3k!@8k6^vFyIUh(aO>;059uv%NBH#~z5b!-^$NXyS@arN ztfp8kT!Of-rrFRWrlhH!@}3-2sR*3|NF38@z%w}d^_zFCjqiFJ!}n|5N2pc(`rq$b zZTxX7;Q2##Se_cnA0n7%j2}|c%_zYD-DWh7@czvi+4t+_@`#s*d2V??!j|!No17e_}ZPdsSw}!x!!M(TYc9 zR08We5segltglO~odGk$m8Y*BmD|xqN7m2x+xFZg)>idui%GWSlZ=VBzV1?AP%b=ik!X?`pgoK*_eqUAVD< zkHvW364cv8-@YR3)Ni7h_2(5NV$qdQLe|sxxSOQr`qiMEQ2;|yX@)lG7YJp0TP@~z zA5k!+Ea(u9N^y3KDg~(uY#@C;c+-d4xLAPlfE)QCD-5GPOSd_GcAC)vJ=j7`09r`r z2ULF>f8cG)!(^6X-!j~2PiF4#-VpzV@>#Tr8|~5LB%XoN8Ds4Z)W)OU`E+U@Zc*-o zbp-~o>-7;vU4m-j;7nnkMfYtcxMf_y%6J(xvKx^b)XeD|jq$Yhbv5E)suMN%QZ@X# zy-ftsB3Y?YMl92uCd&0Gj&3I901MhpAp(MM@edzo8mJ>>sESiZNO?3vr*b|c9M$g1 zs=D@hqup?4BUglCpF#EOv>HNAi-#z%KdriwRe`@vMF2cwHNw6t1pC3ZGJ;(fQIrIu z56$ed{@IWX(cN4bxx+VbGWqqkh7DI9W)$mqdbdr1Do_)D+-v!gE>&>x?Uu!VZt)-W z8+k#fKMAcIGO_MNzeT4<^sqf_(1qK1K|-V1=A&mZve2-RE0#xK#(Cm}j&>-&Fv${o zgBwVbQNNo|LSSHY_;!l=$>5aX(p`ZmtuRUhB)Oue0+!pct)#?4)Rr0I&!6*;3BNod zD6Vc2n}TNNB`s=DMa_9F%==+kdUouk+VuBlkKg|M{KfOfuYZaD_IUqswExSiXK(BV z4S*fNb`}j*Xk|$#zqr~tqHn>Hx9mPivRA{?r<2hrrhWhIXv)2vZl*_*6P*vooYqmF zXb~=IAp1P?`srHUso3S8BhR36kNE~4+=mlFv z#b}-6A?nq3YU$FjbL58x%cePLcPco8L^Jz*iwc!%xw_2nlLm zHSfAaN^~@dSwmDUqA&~mh>?~`fQHjNeX6amWTc{@K0dWx*= zhK2#u0!+j&2SYvqjvmFmS=|``nQNCTsXE9ukMVwm^WxH|*#Uh?Bv{I^F^Gay@2rC0meUTonT!c35rIuch))>=>^GXxr(*uX@!W&; zb)7zd;P!Uk<@hFtwYok4@9I^3j%OcZIl*_n9J~D``3y-X zWb`K^YK)uX(hRd+FIscy_$J3Q^mH>Xl#Ap{V5QLOHbS~Qv%nTAhf8jpS*9q_a_kH_ zvw#nRA?O%nXcCs?Vg_hNJ=i|-2+@+NsTvgA-A{6Ccj32Q{PBj1diN8m4BbzxF&JBo zdiB|V#T=pU4#;}RIIWw&O+q{{go6A%+zD~_d#JYa*8_ZdAOsYCHI#VUjQ)WS-YU*- zkwxbpl8)+`Fy9>`^xvf&5BcIPHWmE?{>5N?`~?yPe?sB6fYBcQ>NVU=A-;G>&)w~t zoD^?2KLz({>+57=IbLWUd~2q)vuTxh{Dbg#TZ+d&3i0@zY&{F{aLM}ndod^;fyEX} zVnCgMCC5k!RmT|%ua0O?*7W2Hab1Z_*U_StrdGX*%WFP{Z?yu zn^L7V)Q#jz?tF5{RNwl9`mt#5qc#Qa?52mhd;MDj0g;{m=cOyJPDzJ{DKCHSrKixmUxbpHAUKN zDaOwT|D}b*ReOFfQhj`ayobfeHfAIf)(6?Lj)rdANTtbkaMqpn(4IObR+&QA`DzmN z^xb=hKGP6sJffJc$ug(h#Z&I$sqLaHbOwb^ckJpqbS}hVa*dU4!Q?`Gd?q5DuCDP1 znxTFE3<$H8v&~1;gt!=}a7j2LMY7{>J%%3hp1#lB;dP;H^nnoo&K!=CewKE7*+Mq8 z!o#1i?HpHjLR_g&6$hMtZH&i^oeBy#os#f`wA}UHYA)hkhu`_zewJW~yN;??7_qAt zwy+#SGku$F;*a0m1(lz^X1znjsqLIm=?N4wTzVWI1E<%YG|A2ml$Z?bPk07S+t!v) z!qIvoQ^M7|9$OoloeE++c~?J0Zk*CQ-9lbzyEMW69Fw@kv_7V!7$lef@8$;T35~>Y z`@K6O9^*uS5u;Do9|QH|GK=1Xw(%9XqJOaaEt4;P_r* zh^L)@>u~Fzoy&|qz3Yf~on<(~lu%2}?_A<{UvL`kdG|YhcHT=S(R>8!j%FqNn&+m- zymMJ9%vADx*w!<=<(&8~&tqE-kCn2S`rImFw<~hobn8Ef`}EJP>t;rJw9csK1kliUm^C6WC5SYi@03!xd%WnyMIVn#P+1r zJyrU{53}C%h!wj2DEVU^*Y%q>aTdX2tNz1}&C?vU#dzGm8&IgA7T_z1a7fzdE&>nD z)5~nZo+RV_SrXrl4ivrz+2T_ts#37wYKBZlbcSRnc%Z~7n<1b!o$h+3MW_v2-IfO> zr>OhLglo>xliI_bI>%0@RuLa~<$CxmU2!7w#Qxt7t7Xi@W47Lp9ORKeQuAz7~odv$7qpyKhrBpeB8 z+|h9#?S&{r;U@KvjFdx#eSV%ir&5+iD&@VsvF2;-02dh}GU?Tnm{Q9yL3 z+3cYjx;mu)5-$D=9Vv$SA;$}Zh{L_`+Z2KC8+(Q)nE^E|3n5ft zDShzI`=}3bmuY0^Q};)#jI|a5qkFLJpqyVg41!Im+j#;bb$(G8=~>!fF}#JyG%m+% z=^}0`bWgy_%ktbprW342OC))hplyzt+Z1jH%xJ}P8ac8Vol4g8R&-`TAXoq?L#oka z@?k!u;NXIJ=P0dmIbDm!e1*D#fxo&`f_Po7tW@w3eXtbK9)Jdvj}R6u#>kn&9>-&j zxM?=Kct&xFk7i@ZoGT ztbm_0l#ARl?kQ$@v=L8*)Iu$-LTzP;G=$P_tWt{%F`%Z)x!T^bLm})J(3cG=kK&YA z$0(^pF8DV{KG}1I#QhIqBk&jSjjE%c6jO&9Fg8#4+0+y(YcJ5CsugT8P6H|B9Nm1E zFj*H@runKIIkdXHf_eL=*K7m#qkIR4_XZ2Q)wygrRtBH&>(;`R=>QXZqUYmrZ_1}l zST#7k9^+wxC&s9>M)5I4KM1NvbqAkEPF8E-4y%wi6<2nJkN=oWEcG^R!x)k|%@5s$ z(q^ZHSx1J-I9%H{OzU*tz-~s5^O~2m8$E8a$JJW&ZOP0=1k@-OwgWshUeFd6DQNHU zyD?cf;FDda&?UeMetP{-@KDD%#<)VfgKj^6`pg7$0&ueqWms)2#Y%V}vXGmq?C&e< zLc>!NX0?LP8->I6Ep5n&aUJ&a12n|Vj(h2c!lewY zVDR2u(eRwo6P}zEhHIiPKYyc$n*3yR6c0IHD0CqNB!5n1Kz16uy!>~Im1fr!q`+#U zCQE>JnovZQ9kKYdI8tM|(B^2X zY;TV-Ds;qld%dO|Cu2}GDE}VvLhE!m9Ddts4ZnR0;#cL?gFoz+>GpVbj0L|1`EvR| z@uzx5m0PX1^lCV4wcOX=D(YaW@CW957=$gUK)L0KcCvT#@wC_f5D)CPx}cYF&w($S zf)EG_34mECfnV^gOA^FL7g7=#u{R%@K&cGAw%I3$ah-;wA1G( z-2EwemzP_OIhH37*jP8%sNsk8SofwO$e&?gXx$J+6jsEP3~BK^&n~=9+;)0_{;p~< zC4XMasPq$0lXA(Bt$)>pQ+78WeeAfMYKldl&gnV%FsiC*Ax*{%s~NRhox9Y=r%k~w zrj&TP7O5%^-iiupfV~QecB%r6v8iNPNLJEM1Fcv#@+uUzBB_E7=bKX%n6Pk!K;yyt z7t`EO<>+U2GrIYPAZBm~a0D$q^$0q2e;`NOlF}`!prrX;sYkkkiE9pUJPfCON)_a+4{*GxU|P^awuoN2RcxWRVvwmmiG?x* z)r!xB@Y&ldIfWK>BP%b_X;^m~lv6t@yRJ;+P%NnJ#bE6^!CD6F-Y!iS2P8au;MT4s z<6)+9SWA_I-)dkxM*FiOU2AX(&U#H(pqB8_>zb>pkvg1(rAf}bK+52SJDzqS9c^rJSdmSIiB|D$J^T( zKgAqAw$s!aWd`lW@Zg;-jy%I}@x}Wc6-MtA?~dok4mew#OCC`Urg!1Tq}{#8gxV%n z_a!W;$Z*Z**&pf)-bHS{^1~f!ag9oIqGDp8HK>zOx}r6zWWN95l+t&j>-XxubLXc4 z^ju}dg|Bb*cilYR(BnXUJU-KfF>S1RM})(#DUz!hp?M(#*-2c!$#`6v4B$}0PX8jkFeveP!Mw31}P8}Pg z379fCt&yhU|p0 z&tu~?Msvjg*o=>-*_jR4(`9vQ*<>`T+tU3mJVVFs+p4vuGKp)J<@yh!78-W>#~zx( z)xIAMET0XgE4xt+G;BZZGdGy9%FHs!v<8znr3{b5BqMGb+X3BbV~U(e)u~;0>?4PS zpxb;Ie4Sj`VD_fd(OLH}9+!`%t&Ovw?LX*Pxkm3d_OdBC2FBgT*gzGMz?{PV6GAYl zocWebDBC2t)7$>5rs#GO8_mx6h!vZPmC@jMKC;&jUONHw97CZEA6-n6cIXNhRkZ`Ch%DGDR3ifZWz12m_6qA-k_ z@x9)tw74Ksd(oJZCgwZ9MBNQ`Kt_~L1{fo|E6-_Eb)MjBdKl=Z-9G4=N*d^&t~{u= z2J5dzB-{YlVx8?Q(RGRptOP7TeV#ZgAsoBS=dN2!iKf%nVU`WxaLKK~=el#4u-+oRQ7Ptdgo>$V?b&q@ZDHd_wDWOs~+XZW`2X&*QBk2JyY^FEqpgfiQEyElc1WFizsKAv_{RM z^ATDUP$(xcCHhd4-ylVhaWezDRg#@a4+r^J%Z9evGVoZ1IEz|F1Ggu|66Q)C zXq7FR8TS02n4ae~Z3~Kit6hNV9-fPg4-tu{&Uy)W{Hy&IDQa@Q_+;Fl%w{nt0IbVk z_IIrWVVpp3mSO%#8V#z*W6P>SI-g?3e7nUC?HpMPL$3)jq#JvzD8%$~N862|Z2SjB zYEaSLNEvQSG!iV~-Tv4lLktDIh#_*KU+hu`{e$8-Y$iPgz_?9k>XsqwI~aF(VDtw& zb=TJwK6*N;5>DW--WOum{GcX`Hen-9_j&qi;@D}6xQI|uD}lo>Q=A(E+>RM776#J} z@N_a_#s%G$cxnNw1o*Qe4+5825hY`#PSIz@boga#;{xpzGef)^b(WNp@gH-%mr+n@Nnr(uI*4Tz zOKNGCUrM-8PCV6RIaf}RvCw@@%;az3?I9WuJYTIvlcntFOfN89sRi*#Lh;P&8m%vM z0D;FSU5-P;vOsaOl1p8X(G04BL8MCc!xF4a?=clS(SQyq79uQ;G&aeW73_tx_gG%9 zrDC(LRc}jSgQyuLpe79pTcHjp&2nQ;-~;k;d%Ff7_L<8uJe>;SAaln+Yjmq2#XHZE zi8SE5qo|DBMyO)xNO;$#pb+$rP*Kw*FxzsZPKUOY+|c8Msrj`m5otDb71ATOjYQLH zw9rW-Ap=O=?&@ux6p(#7E>0+9fxkV3?xN3{-uXze>AM>$KUYJQMU%pBe9_FcwQPDTKe@eXwoA7pCfea#wx7$bsi{x$a9d!xB9zpC z6f;wnG9){%^sL|wHfF#PYQsvXEFa1u&07sypMlG|_2SC!TJLr2V@b3NEtKUjOu#D* z?C0oiF}c~U22)}$`i@vFpw~MCQx|#nFA5M6l7Axe;FIF&YNXrhGV4G~(JFhFB6_63 zeb*9&NGmWMMOpA&n>*YHA-Hru8-acXIMDFkU|{FH+OA3NBfU;eafM7LFnI)xb&I5$ zJ41^-?zFrf>nQAX46$}-*J(*e?HnYZc8gGKXAy!+&_JFc)ua%zwhD{Y$fCVfk?VpZ)ehmqe7Bb4yRBB~7;TmC zT@cA7XuCh3j^azPT~+dgyHqqO7ZE4NcsEHL;Ee$(IG381_pUN6?}zF0$fwSC_sXZG z4`&gAOHk)^JX}N=e-^C%%U`bAt#aOn_g)Wj_<$bWn~yS23$4$`AI6iDvEyQuw^E{A zU{rVAx(ZVBvXzpPp}}`^)NUT~Pk8R^E^Qt8^z&!YZA~##G_dZ5>}R>;LBiH0?U{b| zuoY#*+Sudnuh~{H|4S~IMWnbXN>ronPJzL~s5zLE7}bXNr_vp!dvp)XmU=W94DiVo zR;vFqj!q`C4|qE8@=pEkpPdHX#j0**gh!@I#*xeU;L%Ms&`xV-NjB(JIC`;VLR&o2+M7?MPECr)s}6wxEMgWe#2*9ZC}Ut2NiW;?os3nnhx? zVQy`c7&Di#A@0msnF2x*kAT|ufW-Wn2MEYl0BB|DLV(S*9L3PR*t> zvUO!SWAch}A4V0*cWw2fuZvBRY+rOWnAYi#6;GT?pcdkR0KDjp>~Vfd{;*l^LkzkT zbPn(ER&Hnxcr;>E+zkYVwrP*HgC?Ud_x_s^)7b=kFt&7FHEzRw2y>k9P zmmyn^$7dHj8&DgkaM|eu^Qw+wnjdu9W#`4^H+?3(w;2bQESo?G-E!R@$RQ}>66>GF zF*FX^xqSHiSl7R%{X2-QPZHrG#*zE!l{(%m@~3+;AV!BtJv!-~rIFt4=4{L|L|r4$ z&QZ)R)fB*)U*j{rHld55i9s8$-nhBj{Hqy-{!&CUSQfhBYD%h@YEwZ+@DhUNEFoot;(-EXE*k zuJ?;T@pAE>w(=65l~xh0Ir^)I9h?7jkyAQBSAfrNNASR2ahYG@}HglYee5L-zW`}7H1=e6&81NF~9I{fVd!ROC4mDf)Z9#Dt#~wML zq1dQWjN^lSaltPYp>#Fd&%9WI(zAHj%_hM7lX1{>NwY61a_W|u=V%`C}} zLPIow{a!z_HAT8B39w{Q;_DKDk}C?iom&+=T5OjB7@$j1xVzX+;Ao1V(Y@n_uV}F= zJ4p-i1MmzbHlu$ z8=j8lscBefwuKc#ZF`30C7K8I?#iwE=3@=JmhJ8!u+Lr7I4x@E3u=rX{dpQ5}T(rh|*N zKGuL!1nLA!RE8Jcompt3_>U!E1-E4qSei;`w;ZUp4%cw0ErSl+>J^n$#Tun-agk$> zkYCmTCZ44^YHkUh11y%zO+VF@3J}*>YXpH{TM3kOULYlD8Qky2$%l#dU1_6oJGg>{n^8+#lIbiWHL6?7gXZAkf*!!a4Z14< zU~CmMH%o~|Ae|hOt(S|>5<0Puup~whDiL6wWvB(-`Z$FqH zMw594SRnCe!S2Vi88JDs2FBfx7_Ym~9>E+?5pOl%&DwO5CiJ7h?xm*FqQeZw#TnpW zzws-gf5nLfHM>f8Jd`^D(O3kPZZD!F)Ki$&cv>sI zO!1%wh6$tzzSLt?Pd4LCj?rvb2$hCIO?N<27~&+ZHs}*)E+$6njVQdGGKw-6*{n7+ ziqOOuPlqX4qjyvs^@f?w2W2uaI?NTG1=M^Er9_P)brFX(X@ z!(WM^sY-~oCNNGijE9d7N0S2`1rKzlj8{72o)MZ($g{r^SDjik7(N+@12xG)k<}NL zz`c*XWQ6Fb={WRf6AXEeU2Zkvg35x(#(wJ9RTlSzcvz>Mgonm zvM5fsvug|C8H4M9;fQ{iaRn=j$-4|tHYp^ex||oq!hcSd4K21*S{8264etJpvuz&4 zL-flyh;a=yf-svbSSJ`FL2zxUxqV()m&M~87+58!=ae(J3(JnOmMzsqTt;-Cv?7Q= zYXy72LT<{%D*GGaXZekF!8!9~B>gqW`o+?|y1ZXT;)gB6K1X>1C_jlTxQbE9C5Ka{ z3l8eMTXirGxt%YCz%uQJNEb$+(9|9_tzFWW&L5IXuPUaJ+Ozl#nEL+vz~Yk|q|n-v zE3{y8FXc%pT{IRg@y#F;2V(^*Dc;zYkz=5z_Qq0YhE0HqG>p>8EX(D!bq^(Q-xPOs zmcB0Soa&VR{&qBqPjiMXYs4DhK4?4ohJxeN59BtrHHFHX*_2}lsXyK4SV*%!z6PY@ zepZ)nHLm$Z*XC!$s{Q$_-q_@nI-I-CJj67e2nL^w<5T6JBidWtUN!01@>pUQ)SZaI z4xmhO8pHQG}W!kdD87^P9<-Xm_z@j|JH4{ACw@2XXB$xHw}$%ywcyUwf`seLvje#-1zSfS>j2lIZHir1?! ziEyrww=cBeWCBn??v(!FY#_UNzno3?!(CS%UHhsJ~HG@g-&9K~5C69|{(yi`dh z*%ncjYf_E0&NPXSXjAT{6s1SG)S)GrB9VvBZ!;v$DJm1es)|+$l5&Z+T<235Exaf` zcR##ipsV|tVeWnBWrk6QPXDbAo#=uJ8?dL`FADR^m<5Z$P{F-DeQ6zW7d(0RaMxz! zSzqt_7S@%%56B#XUHGy>z5ix)Nd(gjCRJaZY*XOlQGD7RB!@|szQe=wTC3gJx_j^b zgKxj<9rOp{Xp@^1#dR-R@BLoh&2>$TPq=f23!J=J1sSatB&@pYjq1DAoUAQNwdAJt zl5CW_^}(<#Vx@0+_uROgRdieB*!3`sG~W#)C2!3F1S=gsVYGV5SXllYv^t?2ROi7Q zR18rjXtPyvyEg>0odYA61(TZr?ZXs;u2A~Z>S~Koz3|%bHYPWZ_jmX5h|AN6FniUa z_iB!~l1IOVIi(dHTKmE{|<8z%$@WN=WALH2po+X}Pt|ucDoO4MAvP#E^8UVdmZ6IrylR*%y z_#IoCMJCzB{2cgs(AT z)01M4P%m+}u|gM*e>MxLa~Ck0dE^7#)!@y{MAiY_M{b=(sc}2O+(j{sGb$kKI>Iy8 zTPXrd@?;80B~IW#U#%ias2b*;th8E61s5y+79I5l(RhOV)3nw<;fUfapuw(3()6gh zUe^=J55bT=^>h=wGZHYwB}6PG;TI>MCSQtMPM#6i1w*=^<{=lQK{6Zy-9Y*eXOm+( zW!JxtPR&15kX-#r-aUfX#lZfY?SLk4Oh}u{D{{TLa$|~iWz(dSaqnp9 zv@T$IR76>m<-RBL+f#<}y3B?hJ&HJ^Ic#uL(sHrTQP%ppD)8A9;3YNixSVmg-B3RJ zA>BhRO?H!;;3L6LD4%V!Op~{2{PbwryMM>t088E{R0hQ8RkT(HmF; zzR;0!Ax#u};F#cr8#Lt6N`MHeM2a+vb-}u6>jr-VlFvY$*4mIe zX^MstQ3}(ikbt$&k{-9m-+J)w01~dQ#_i|9Ud}whxlzdMfWq ziJ;!dsc#F2r`jqcGT`Idf`z7WKjBkKU5%eCIDRUk_zkVuHD0feF<(ZcaYkqA@npQA zf6M74HXgQ?0kL!WhEMfP`8G5JR#+D&C@u>xcDj{E z&b4l<6v>tvY#^_KgYN=D!>{f-4DpLzlB+VxaMN7IhXZDRAWK*SE8h4l51EAS$(A$o z%P>QICD%C4nc=2pO6NqqwEtq`N%ZEYx38Z*i(Wl` z{pQ(g_3Dn}HN)K-C23abF|#9YpyHaCEaL2VGEW^l(?Yi!61bCTJnp7__&|pY5@?UOo8Ku7;hBy#ni-Gf`F6kghrJ zwJ2tMmXnTu~er%3cD=Qo34%Y2<|kGATi=j+Uc2{Ix&_ITsL&Le}K+*W5JL`+?zdh{&9BeHi9?@%^Cg}jK~!xNA!pQAtNUs@=mf9>a*%i>w7gPwFzIQM5O zs2ZzvXSQ13slfepqJz{_KXtA?;O!l&x%k*8nuL?yK*XrF3{%P^7;a(cdpY^wobE#Qj4LJo5l_oi@V+D(E7y zuft5}^3ZWRM;G;aE0z)Y()e4+(r@C`W|)C8>P2`3InaUZ?|l{FMW-M-1v6hS8@x{5 z;Wd4iIW=Pvp_sHoY!8t~&^b!~S;!(4d}xcjXraq&;;^oXwTA4AK}=>!3Qs+!!Q3t9 zjw9@jF0;f<*z!y|ciXhJDJ_oZ^IdCw0(kDTa=Eog<{d*lu#Op|&mF=y}K3~+@_P#^S(hvM~~ z*JD3`0c+zi|Hn*OhGxp2760naB3Wm$9Kgbr}#DE=6a3_hd+cInxYjR()?`~5gg zBWX)^R19V7LEdgV)he>z089*TGv;Xv?=^|*h4CO3FyHaP$hw}C}5{K?qy zf_VM+Hwsd29kYvdYR-puMc@1|0sY<-EWq5iN_{ zzU^SgaqP}u$#9Np>}up>=uhV4=&3FyV=shgKE|XynA;^uBNe0~a&=%b1(-@+#7J(3>{-tn1yC#nT>~^_Jp!~07_9BkAPn&PH&3$#^Jfu z=5N{=B6XWB-&1uKY^vH~Q`M=qs}gays@CPQ?o{co$}j`O*ST>Dd^AG4d}^SsT6N?l z=Skr082{TbyRyoAXJ?bFrfBpC{(Bc~!@mVn_1-m1RW;`;OjfkKJ~ESa39~@J0#JRb z%ZW~f3}V6gu>`mL_UJcujl&Z^z0@%KILCeNq*!uFuz7RAjL@tvGhr>qggWv%&xTiH z!DnH{Yh4%P-78=`73AgF5p^hRz+w=7#dbXZ-Rhq?NUQ%^b#9y}Fsl^}eraDS2*kp{ z?jFWtf5fg|(5w}V^VYSEb1Pua4UO^IjVJ@xvzq?4cGYFGkQ7U-nVozeLfmsaAHnEo zS>dxxF5oOAftFtiDbqu+wQFJ1^#V5STo;>eRb|ulFR8Px-<-~x&X51yI_huh*D@boj2g%SrR>4dBu^HIhUsFw=c zkC%S*iYmX>@kn@Vb71}WuBh-4p_WIFGnx=JGTIqF7u1KxXf?!h)g0*6*zFO(4B=DwUCEYJdJIR-ScE- zsPOLkJAEUkN}Qh4Q*XI3JVo+XmdRhcWJ{#;gIV0y=Q=h$lygrQ7JvHpXHWlEM~rA! z&6vGewpL6 zT#dZYSiR5!ORV~ZsQXqnl!*(wBgMMmMG-Z6P zC|3oujhZEg)`>dW6&}>iGUkM!6|?*!FXQ315?R%^Dee>t=Tws`X&#d|Dr!lO8kMJ4 z=q;tltHKPO<9h8V!J48?F5#lYySn_Qj)LYYrrrQcK(xPbqW3t91|4Wn&I>==4m`Z2 z?jKQqWx01aqL9|OfOEf6L`D1Tv#k2+30?rO#-Q*eEKd%5y1`T7Pyi*9q#W8U%c+^4 zl=Ff~xzwDb<&SvRCMhhPj68Kn!w*axJ1s=$Utn)u*}>6((VL%;o8uDRhc>d#8p;YB z5M4%I%I8qT?-e>8UdSmW_i`6rFOA2S$kPaqs{4)kzJt{`BcIQslrJ17z-!xx>aaE) za;v|~cRD{xOWQU~)P*i#<4bc}RLxRuIK?uQx)l}vRn18gP9GC?hbuDbgp|M?qk_1; z)H(lYI~ROUQD3iPuC-fYq9d_N!LhMw^ii}0OP;=u-PS5KVvp78s+dV9&^C7mD+sJ` zIksVY4fi9bD9@g4b&0cc-GJ19!*^5J%e5TmI_KJ{9Rou)8@ysF+*-~(S;EOBlNY+J z%nu>!R6EF!H9R}xf?I}E0&o*aX@h|+OogH@WOCKmvT6*xayFTW2r<^rRN?h?M-WH} zS}+;pn!96n_bdVy$6p!C7FQ^YoC-8k7)<3v@VT1jRm1mk(Q>=M{em3|%c=h92j0#@ zgnBwro>6`Or&rO7Xa9KiqG2OGN&c{SNGJ1IU*$STI8)nNl%z`aV#fR)WZB>1v=0Ji zIKWR8yGgn-)qfrL1~J}%g&*fwoeN$VotpMPI0)xlNLvbO^~U+d_Rgc|oB!U7{`F_{ zO%0yixkLZ1;lFEln6(2El~u846Qg;Aw_YO?;^-f8xbhs6Wd541x-W2f>zX{1McE_W z@MB3?Siwd*8#ks11`@&pyZ)?Mj6 z?&|7TZ57YnhL)S6JB@-7fYy_7Jz)LSaF{2OaWh1Y8da|`zg{%_!0PD9+vhL#H=e(Y z_J4WxEc)BC@1MVXzW@BEmv8KJV=YJ}5SIbLGQ~)wIn8m-r(9vmzASUjvsIg}HAexW zjNAa$J}S|KIP`sd#%V~+RhcC5(k`3FS|&i-4UlqFY_&T8Evl~3m%5{VCNj7gWk1o0 z;v$vsO z;77V*=$vaoj{BnHu0>hv5hEimh(SdfGDcUi?T^X$$KL51__4kHc+A>^Riq4m>ktz2 z02c#s#d;x3%2P4xjSpi3tjRS+Qwv}WF`)}pt(%&<_)!nHEc(3{j;Kc6PCNZ|M=T^1 z!f~NxhMHf6vZDGNb?2u(+HrDbEfd<9i)_5gk*5Ue#8Eld8{{^MR^9cIftYXvZIX3G zZ>rV;76o|I?(Ab+Z)0X>LPuZVf!zqm>>8;kH7#bgI{crRAkOX9g)j)nHx87R3&dPQ zT?pf00EVso$AZecMYUn#l~#rKiUQUM{xlwqN-JT3T&?Hha!P}^(nzW$s&nswAygAJ zX9V+h5uAAl(0u`j;XHx4SPBOxs|Tmu>TC%>fmNVQtH3Uz?koayVZ_0FIDGf5$~c!& z!unwyAL9L|@Z*05(3DOf8o~+7g09pSq=gFfe}_hDr2xqbc-R?M1hNpEpUOYjRU}G5 zU)!B-ou3e$`N?D2m^f&QGqB2{-a{g{wOWA zTeICMEBCNwur4j8;N>#fxQ8*`X7uUbpZy4%(bqpcefH+f^OrwFk6-?ckFnv0wpufoe0{8yp_;@nz!ak<%XOl9yyyxahUj>^@U>8c|gu2mgFnyXvF3{n! z{_31(769r@&`d7JmbS%tYbq37aP2{FaGa!Raxl_4JN4ZF(4RqKMv3(PgOtm>yZhdB zP7TD#xjtqyT4zQg?w&9idWREv zh;=?KGp%w~d2?q)D6lpXR08s?uj57`lj_n+CN-rT`8WHcxHrR@Wcw1zq-Iay5h#t+ zuDzCpwu`X&{}9%=lvM_6?J;#6tntDm+R*^H6u^xQcrJG@EAZRsp}9_AjxEsz@4`dc z$OP*goWU==-D`}J=$Gy|8G6iB=)~XVvpNg$4Mj!KZo@<`{fWo@#fvGXKMoBl(G9v97oa8+C7hrpN zA{x4dV4K$IoDlCcpslsOsZH$7WAr!)UyQUAIyfq~^*NiyZO2L%d_>#$%^})Zp^XWp zn*>zw*xSAa;!Y>LSExI;?aDniVZAMV{|JD4V`=TTn$e^69~yg#8jBvme%yvDW2ABq zba*r^)L`P*qH+8&o<)d1l5V0hZ`Qamb+#33(lkgV8^4Z?Yts5U4}fL#Lcv2oiZ9?; z(W`Hmz~*fMeG4d@cNIoJNM}qijsAy&1r%2_54V3qB#$(rL7MZO6|NhYu#uE|fN^F2 zvJm5u>fiq1j&H$-j zKV#sdf^seX-npicJ0%6IkJc3tx zO|6ld?WdDjhDyXH={ogBlfVG`s@t{b*Q}SS<7CboUsNGq*(Q!Fr?~1n8Q~1wne6Ol zGX0plS2#eCfaY-!&^r=d^5= z#6oB3r}Tt{b-_7-?r7j7$ljCm?6-U&zbrWHS4}AtT3=Sq$)d zfqc=G|Q7JGL^7cB3cBcptujlpLdd9<9AcY2C&etCEeTZ=7jHpVX** z0{O0JcHxeJrpP>vhx1W)5KqyxrCYZ<9r<49hST9`7lr1G?msiNhRT_B2>UBWxSsbr z@tSOffm#E&XT7F?YTbqw)5XlUqm;n@lnyHca-K>k+qsK_c`BdeFf@WcUsgVMAlLg- zdwr^RZl-h@XPAP!M|DS`tq5a%|1N>dC%c%z>U|m!Yau&2{5csa#V4m+=JW#qY(_hv zUOZLf^24k*J&Lf)eKN<|IxIVxK@PE0ol6xumla62$I9HEj6hyK9}g$6$Cg-z-a$^gsS38s!8S{Qik|FG`NCFN?)Pvx$1zB?A$8RvwsH=( z)Cxir1cab12_gr?;Xx0Ow!BLtK2UViOf@!$=DL<6Z^P@w74ct;c_9f&o+|W_HGba- zzUo+AOtf3v+C>4)yft#g0P&YfQmUn>(wHb|W^Ny48L;C_cGVlcbBXacLN1By({__M z+Y}N|oD|hS7W{_n59^lt=Bajp#rU|Feu#vtK!Q12%&*^zs=+wQWhSs-w3-B4_8KZV z(&bH@AqbEq=LV8?B@~Hqo#|IFcfyU%Fj$!XQ)%QZL)CmWQ9o2`SE-Lf0KhVKpf|C(D!Dpxdqc=dGnf^BIiBM zJHOgnZIb`Y>f=>UPdEiWLQ{lmlfsL*)kWKdhNkFGYSxsc8_=P>^>ws)!SEQd)B2->a)Y~Szs_u+=(Q%hiw>#^dHR=!bph$tZ$d8g2Tcj*7 zVTGRFT-{{rT=kA=EqaAp2-6XhiR=7D9vQs zs?p;O48U?NxlRKcMYUnaJljxhDkE=brxcnQl}|6o^iEgY6f6t63k>2L>TN=Aw#&{Z zRLoLjOYm>Lkc0IpplI=#f^*47^oYx_dSj6a3e+G? z>(J)iV(snXJ=kV=t-1bpbxMN|_)uoeo^Vth*UOx01v?!)i^`d0>gw9;;mLrIuk+R7 zhy+OYK|E{xI{uY=LtjjPN=}A6MG&g->|+C`!N;4DIfc)h)h*Dn3#ZnvSx@eNY|D8U z(c&A{Dsx`G^*ryXnG}S!9<_P+cFWG`d=pRzR6Yc|kO2WpD+lE{An}FgT}1przZ=95 zwMIzX)}_w|*MVOVxecglLHvqca1fyDh7;q*O@8YwUXo~I5sWL=u6TvN z!(#x**WLS{c0G{(O;fp3RjJt)uQdLg=7q+9$yaxmnOt>RWlE~Y;tZuo)Uj-!qBO8k z{mt_qU%hx1J$w1~M;=^w#y>)X?6vB+oV2TnGgeHK$#~mlEs@=@7QSL$dG-CzbvqB8 zg9IMo(&bzlB1_tM{QB{a<$&^b*lHds8I3>}t_4Ry>N0#+T!f1od&Fq!6=`1)Y>(%OV2bDMT#m`}3wf^YoT3MA*%c?{#o6veH~7|0b@8oKv*p2hV9QTM zIe~6|+h1Gr{$K$nO^YN1HI7y79^I&nB4yQfXtS8S!^hq$LMefaMW z_;38sbYu^HP99F?*>s+5=&V0`@1ygF&?EaG+T7f{07l8Rw(;@T?D-gPKu_by=8UAv zaD(MRk$waFI?7!Ng6O!H^^YQL=?m8Qzb0il7!c-tSwKh=S#%E-pH%xE$m zoi&0mj(*L4;F@vtbbUQK;!IhT@d#_7jy{L^b{1_Op+#`>XgUo;>U)r6?j#RVzX-WL(iY2#rt?0R0BGlyn$8n+(`Zp5F>|1n&CV2hYQDnACLr7%l6Vl_k_6jd>WKtg&SC$k$N&)ElGX`>;2 zFWOepGTK&Ns zv|6qEckf2{`QZLN`fPRhcdND4xz}lTqW0Fk2d%sK|NBv^)7rXs_rIdnwe)bo-yF7k zGeBjER+*A=P;59Xc~6~bMdtG_@`qb6_}f29Qr6Jn6T~hZhwuONGI}za^gn=_nT(?s z$-%5QJKMa)HG(g(`fwJiFo%5sY*u>X!5x@*$CE)a zJY$)ZMe{LkI7n2qZ!JdAtNFnw=|j8ycnre22WaDy^av$5 z!^4{2BQkFkGSTQ5g*oPUaO;E6bF__V)m)W`t zDPlX0w~A6LN0TW<8D!Y&lVmhf*NzV7BQ~-?>FA%&_y7LW+x_VA%U_~@K7RfB@yq>R zcF0tQ4hyh>WLRW;0npIJS#J!h#bihzeth=&>EEHw<0sEwJm3EXw>#fI-+%e+&70`^ zpI%3gG4=BP^QUiLJboR$di(m-Pj8-WM$wxX5#wF+V!97$2!XVNIO`>&RMFxW7<5pU z=A!{Scfj5(20dUvcK}V#Dvv7x>ygVT*#Zk#GK!uL(LtpdrGWjzqb!?l-??*gaSEb6q{4>sVR@1p&96dz(v`Zs5=W&-=Yc=77i+MOaJ z#!*ea8Qhs?K!7`F1TA<)x&VR30=HaS39L=7c?b5jg(jY-(<$BTfiAQv3o0+s=}y4@ z!_iaSX*PQZ718zJDJ=VYdlA+_^-G@poRYgUQYVvR+9XKqvC+%VQrG~DF4oq7!web!U$Guklw4>5_O_Xv^qpJ}&h z|2cBI{|x5REC&>K|Nb*1L#`ZJL~;{l6;V2_CyAlf6j>^gKx9mq5nMnkWBq&s=BIs@ldfZg^yUcZt7b-U4 zaw`4*goAR?OxlcQY&Yq1vUp?ooX+BpMAlp)74}))7H#T%BUi*4rZ(>tB`|A?BCpu! zcGNokR_xyCnm~RWw^SOAzT?K!qZle2u07Q7<0AMiAAY9< ze!c^U_sXu^u zVu&Hlx{_{Qu@G?M)ouliu1Ak_85J}zNjK^46_I*Y3b!Qf9!@5MfM65yMaLVe1N6Fj zMcJ(aYtbg*VN03ek5=lSSIv521>+hBD*Ofm#VxP}k{a(Vswkn|D?->@&z)5UYsw@o zt#Xnq6eQ=b3bGwFIO__sWeS(xs#o?f%FHzu*$f0dluWq3E{2{cger7|x$OQq zOVA*2u9h9n4X0H+QGyniZu$wY+5Z38d-wh(j$~o@`I}EMR`xL?BOBc;8ylM!*d)tu z*=&A5Fj{24E;tCVm6{Ud!VvZhyKNnqgK-)vL`S{2WXDE0 zWiHIEM%5lHP^F2U0^&EcR{OD1y$&HeD^`Y>f%OQXo}%unFcwk?BaK{uvQ2Pb6LqCb zG+*Vyw#0Z^981*Njxug)3u13IRdqMoDK+(DjAHzEig-!(gT2v`e|APy=Ge~YV~n~D zj=)O_Rd?h8R5*LF0t4<{X<=AdfS-7{rv6k&s)iCpkWs2eCjdzXcVSGNY83;1{Zf_5 z$ol|FK|0y~^)G!;+f{7)Zym|MNBTKiB#XUaTg@OeopzN@eKp%Rjki4KlHilp(_;Rx zhFB0IdTr37RuKvBSkZtW4;BIzuO$I`wL1lQ?Lx1p-WCuRIv73LEM6|1V7zLKil5Nm z2rV%WCVl}d`m(eg-m3NVO}RJuZvhqXm8vnD6InCG7msvKKqSq=lGilRfWW_*D`!k(B-i&I+R&sBGzPCGbIr|k{o)pQ2xw9P;= zv=H}r){HCnjG{E;&Pm0+gsdwJ`QivBvPk;`1N{uSa7<58kR`#uOCQ}x~>=10YxiN z>*VV-Bw(H+g#0Q8eY#jAmybzmRADp?2y4gK_PP&1Eq91N^B2>lU{i$?7S!mp!}p+q zCUEe$O9Zby1x=8LIBno1s-Vd#)J8u`6_3?vJMHv^W8H{eOaIPNxaAZpxg{EUyqdnB z&OYFi?k?<()1#wTIKVAYkYj-u8aC@E<77djSM*gx>5*hkLeRXVgRF}YY(fE6&zFvH zstdFbt4p{*YDy)MGd|3RH{Qk;FLs!%6)%%>aj1K~q%@W_-r#t{dzXPJ>YvNojQ9Z~ zeT1)FYAQx+02enrzmASDzgsuwpedLfst54^+B&faQxOQd3ZE|_YcoOS%-XsBD*qkq zhTTU(loz6G>5_!acTZ_n!_|09667o^*X1_r?J6I4v_ll~%rHgz0I5Ee=l-7hfnJd) zr5n1$P?#iTwVbnnqKRM{tgZFLPo%A#i)4(2Jv(BMmyXo-NK!)L7Jikv(Y<`<+y`Cx z28AjTRs(9!h>xx^vRgo?Ra2R_c|{kT$F@g&Fe%T-87v5?xgPNRtC5A%uwR$<=ISP^ z3yYefD75A$js?q}Q83$1ZYH!5zwBe3CFWmVrfYi)0U$tqUGev$u6mv<*7j?8!!5h$ z_7)h+=$Y~<8WfIb8l*!GP02ePOI7w~s>WkB2Lf*T-e{WS;j81o77UDO=H z5A{k7A}?FBxDJY_S8VHgAh)!dC!@t|6f{sIKvyTq!&N@hN4hM1M|BLs%y zN+&khn~!^$IPs=~wKqABB<3q$i@`uktN-rZF)-3kTc7#zMPNJP0PC>Y!fis&3c9v%&xT}lGCS9%( z9=4Uo-idB*(%q{r(LG(D>wJ`q6%*F0iTN!l&axO|kFhMfk3lLp@FE@9@BQ+lk~0c+ zraj&hxc1@w03Pu;-=|{9{N0_e=FcoQ1q8-yQ-Y+2&oi_M)^g?|D?WS}O_IxA3WPlv z$Z#$=C2&xLh~|sggq$pK0DO8+FP2gKguMPk@tF|S6b**R#|qLEh#zypn*h=LVp(zI zXKrFAf|K%zi#YCc#k$03YTPYLFK7o!bWKTkuwX7=n$2r!nk_`+up>os0h-SD&fy?< zZ6OPBuluGA5}->r#txey!yVVgZ9GI}Q8Br+B?8oRwzVjqEMty#^{j$WREk`>_3ej5VVXPMYQj4q`USP%$ z{0QzFvFCFsSY3XcBR>$AN2S-Hq|LEX5Q@pwd`nGc4Yjtv6sK)qf8<7DnaIsb(%*QZ z{|a{$`;6V|OWESsFgQxWJsb&;yvf?eSHlr*RKURU(qkR^pm6lzp)H63G zZ$j)QT{sZEM?DE_KV+DDqBA$kS+f&d6Sd4Itt#LHlyZld!TYZ}t3z zu~T~UGd_5}FV9)P5eY)E z?*4EvUI1tAsH_Y3Q-QNPPhh|l$YIqT3~`<=l!puxOt(o$w3K%if3vOUwA6`F=&etl z^cti*pX6wuZFi*M9#f(iLp`WmMoq{VuhOkR$nZYIRk%O74_6iV=^yviEzvg#`=|ne z@(|*P8*n1}7;Vek5ELK$*nFO*?_j^%HPUyIk`YZ(Gl3^2r}=Q5^c|}+)jio(l!g&) z0RUi2+UL}&^=2>~aJ+|0CfAFopxOR+qab8r*l19s17dfj{`9H_7I>9z#kviMwb(j= z$Ps*xJb2KbdP+<=CyP~hvwIl!+~hC%{z8#bwR=IqVp=G zAS#crWe&oYh_L^55w^^o5fS<8`z}W1`@@!@r4UAe3h|sTCKL0ZY|{%PVw9vSg+aIzS~*ba<7Oj@rhUD&iH6MH;-Xa`#;n8;8EGIrikD6DG~%jm5G zE7)pjwG-4Kb8lP4hZ-hOhqCiGXw4gl&g^L%A*qX{KOWQd;OGc+k)2kw8zDNt#=8r; z2q6=`>wZiZGceeiP4UN0JN_tcaRa?W`w;l#g89{WliC~z?*dki{sdh_i z@em`E$xJHG$LW+mo8|4hF}Wk~X2+^)d~F|#Me!`YxIanh?GPYw2nKf&`FeHrTm#=V zQH{AdD|`_+*ZZa#++?@29^ikivUZcbqheNI@kb?^Ex}S)?>Aj(ZK<;ri2+U8qveeK zQbH(0J6TWMGV^@!z;quxFCILwKHj4;1BP1Gz)SQoD`vX*W4E>?kh+c3qYf(%==b5P zWZ23fRAJSQ>`F%j-gBj|lhce4Me?s!A>60YOFf>cSA>E;-h*1lENHH^lI*^4sl zABvCQ0hwa_s2F11R`C6nLJdR| zt~h3`T2=MVi@~!Z7S$Ln@d&Bb?Z-B630So_NKw;$qa(oTFtl&;daoSo2=aEGU4`hA z&8emYL4=+K@t53(!T0P08rjlHm@W;?Ef;$rM*wTNJ{ds|*Cr#3v>8#x?%x$A9rOsi zGPi|EbP~d!Iln*q?odRF52c3=uk_}; z`IZ*QzuVHL)b^75FQ?u05V-(iyaJ&$pJrWJ?Vl6!HuH4a}CCX zanu-=@QFbz^*(EOC3DCLaSk!ivJCQBvgR>Qsdh%vySZ>Y? z@8#Mu>5imy2+s>(?_FZGh>m5F^&QNNO-qQfqjw3^iR&rd>|pj`3Ip0(k{F?k=L4qz zSW-NB@+7!T@s5R^Q3{z~SInFs)SuxEmT*OV$WUDmu%uABvzmW}bTgHket zQ%mDaKQw@p@?>7#bht#775;{S(=@x^;)Qv`s};2YfNnvX1TW(x>_1>ndO6dDMjMWU zu$3RkjAN}TUQbMarB}S4?STn^SY%R?u}n8l6w6c^BddR#8fvH-;;`A@x$qt*l`inEc<#MljKh;CxxTn%3Cr?7zkk z`GjeYu=ez^x8Hhx7S{cgwv5PA9_h5ZE5uZP`h~@=9i~b|MX3pr?i};lT2)=r}&Ho3ZmICeyTNLwodQD8nF}886V?yRD6fVhf$hBW&&C6GGBJ)=- z*>hMtHwH3c4${yEn}B%Rv~+^k*cU&uY)!drO}1=JgWK@>&YSk)vgOq)TxN}}RW7m4 z>sI=DYuya4wfL{;8CR9ChvLuC-pc2#efFmL)^y9u>u=Z6h25Z$*PzK7gh{E%Ns0Ao z+5Q<~av6l7m6oKH79*-wh^RRA&099ehOqcF8)#$~`fbgdmk69Rhj_ zw5>+jnVqE^XbHR?$f$mm0d7~AU}$*;k;qLFWO)tuQb$-01#&nwRhdpL$A=AsPQ*l9 z{W%hYoXrLV&m|^eiynkzNcTA(lCXh~N$`0OQ&FkZiOCXT_m;k)>pe@ia|p>)b4U<7 zEGy}Tsn?Qk@nu@a`LZQDrb26bk0?*UUBebPD1_8$H1hU748dNxp{=+&?KZ?k>8Wx1 z2-x8OQ1J(7_@TI=MV0iX{unN3;yV5Te=2&q4hrEK6=eS=MwHmM)LUp+^pzLavTrG@ z>~CfzjsttCf~g{d7l3oTI_UdoxY7qxiLL@0JiR$m)aGPc{stzS=JD6YTi+?#a2d{8 zdY3G7HJRTy?3k=?kk90*h;90ou`k8{;HnR%DNkkQc@t30-{p*{HrlnQ@>QkgfKoM) zt=4qVg!X9Pe1lF}*vaFYbD3*@AoO#`>{Cb~U<}2=1z`f{ou~-`S}$4O zgjn)MpCjN0WC~I(<-ZVA0{S?BSm7dXTUFm4Z>HR7Zq8J0m9I3f#aFTd#!?G>Yg~uv zgbe4~j^TWmF}?ZaZRjNVt%!Uroi{qyBXlLKh&h9p(R?fZ-HwzfF1NvXa1We+whfS9 zrE$$Y(z@0jxz%mb`l8z;^sV`pCi8jrk*@Qe>b$2q@9i6H?rwYYUSIzTu0y}Y##_7h zI@dg8oV_PTifI#8aSQ%IcA}}Gsmr-lTRYYX@69)^ck@O(4=(t=3E`iaM!M^;>N*iHvj)djwL&i!#T*K`)9^w^klyswd7HmFZ^EeLBZRb< z!_kj+FIWSg`Av^!TqtDYf9a4>wpA(2{< ze$gDNPimli+o-7>7(`m8lc=^G8Ig?}DeL?7*tuW#-;Bv1U5bFEEcEIAek5UZ44}wT z6z~TI+tcWwdJlqFwfIeq4pW{w-Uo$q1#mHX%WVN%ia8=npeo29bNS==n(PsD0hp2A zuiKY*#~gKl&m#Lqv*G9l^4Vhpv{Keg$n<8a}0X*op~b(^C(VtwIt z+<#5B$9L1_Nlt%?T+-QJM;uKGI_j-~_cql~lEehZjigSRqvLxz~F zohVrtz?OeTE1k&>oxS3$B0sC39|8t_=EnMZ=(4w$-fXbml-O7g=Q`Tv75~^II#9SMWiW2GF*J0Ta^Ws-gC|y^J?QQ0@W8yBjGa}(&E9|ILCr2f+ z=sYd}xn2k{lbOgjrEuA)DW$g@e@HH~?pXqU9WjbjTKF=u2#H!SVHXJoO93$|n{am& zI~j?Z40O+cfFULzF91g4rrh4K66|bi8u(M%0ywxd7=5nLg^WycEl)=Nlo(nnM1S$2 zYZf#7qP*d}a=qh@s8VkHm3+%ZE(tN>-Bb+9CRZ*wgt?Kt>S*Ma zI0Gb6W84uqPsM5AZ0xXM4Ck>(IPzBMxM(|H1Kb#_7Ay)hVJ46HHE2#@EUCqvNjoyyZl=`w;i$gHzg{`Cj{#g<&aWukvl!`Zz6lj ztsTr;h)33J-dmtK#M-NYW5#NU?nbImlZ1YAXLMDuVY%{&MFlmlgb)D|N1!|3c67iu z(4b-Y;~OV?N8!;ZIMN%yJ4y+H`8tzY^h~Kv3iTz7elP#ymF{>Ny^p++6zSbUGOG zBkb9mU+~mwMmrSaR>(W#S%ydPz&0X!`sNp-_{l%CV)rTMfGI-bchbv<-y zXjBg!=WP(pP0h-=3#SwhMG{maI3?w7w&CgASf{1%XJbtC%jlGh`3(9HdE{nPELg`0 zVj)SHQvnWH5N(SO`U?iOux)qLpVD@7)EN%t_TutsyJ3!$Y|gfkbF|$UB}k=&mhm;w zqMgbNn7?>nu0vK(wd)ME(SccBW$GWM){?juR~tBiSj>Gqo4sGn#pnaN3@&5f79eM? zi)VPlGt-*EdRHd~wDMi4SGB^i=mi9%J&M2~!n?$~NMQ*)*zqmR?G0n=1T*)UnWV@W%B&I}Wm#CX6uA9xH- zby4D&w5SrB3D!m}LaiwtCPIHg=Wy?=aJ+$%8flM%>tJ1{J)COgCfM%RJRY}M} zJPtg?)YRMk?e7vexE?&%z^p2?n}Fyw$!mh&))ddQZmP*HNR z?RmIC)z$RU>PU4X%9m%#cG^X$9s5$t3TD-*T7kuYivNK1jECf#`ddq=Am3U@$__Ut z$lwk)h*%b{sQAYh(Uo%(1|fH(qsrqS zDW666nWTHzRHqe>Ct5oZf>MRIBc$%x!OZZ%J*iaYDj&T95tWmwy~#FzWRq1MH;}zu znlwZ;GwyND0Iy7jY=sL^^tzH)|Mf};EN%-d%y092HXUGWTBjM7=Pt!AG}(O)^E<8N zSTD_1OMwdHy)gSw{`9;xiNwi1tEsoO@$3WP6T`9F*H6N$_>e5q0q0s6s(^6FT0Be4DCqbm`6a? zjm70-OZ=c$OVL*O4fj3BzDL%RBWQ4_AwIV2>jOQ=+2S>Ym{wJ++*IIr!6bBM%5Prm zhv(iyJ>AHM=eD@OPn0!W11VKwNJut5pDJv3-ThQ7(6ta8+Ph|(InKxI=WY?dVsQ0QC z=`^IdCmS1f+$g~oDah|7Kc8-8wzPHdU*N@>+a$$qHDTM%z z3xYP8I`e|l4)Kg3j2rG*a;^^%ySB|L&XIna?GTr!1XSN-Ky_Z_if_g={O5AH(`7TC zzj#d)+R4&{vA^}(W8deNK5493?oDY)Ez{AuT@Z}S{8(oD+ch$!6v+dbN)m{#YqHVK zhQWJLp^$AP>5-)>2sw4QS#hbIpAQ!wkw1bW2XD)<6IvqLg0Fr?2d$bK8tKv71SoIe z4)En6e&b~~1gFN2tV(%VJ=~Y256K_WT#(m1hUDI9l+eS3O1~0HK1BM9Bez?3A!eke<+5;& zd5`YU*(*d{MKI?rcPU`k2;SEtw5ERx3f~OYpu7A9VPm@T)I7H#eUua`82?%)UVMfX zfA~;vYI+{M6-jk-5w%F7DU=ma!RWSjb%;zb*AnPP3J&s`WfKIAg!e#oy;Ovv*HxBw zm$O3bk!UsY;;?&y{#IE@e`B;VEMl^*>tizJTA~P}qq;Z{HEJ;3qsT-1b?_cY@H`l3 z0a+T86d~Sr+3tbc`f?^sQAn+7uY^8mTb1~5+T6sAZ47i-0 zmQ~ce@N^o~L*8qEQGAPf0X?^VE#Pc}2U2y6e#qg+&ZZ7novy~?`Euc%{hp{DWtm1T z@!830++8%J2c?({bGPB^%8DfgI@$|K$nbDO#$BIG$cQY1fDr=fD{BGyN`&^rMGc5w z0Ok2Hm3lfE49d}PGlyWK9gkpZ(axnSPURAD^gq$1PtnMQE`o|`BK8l-9ASl$c}nCg-xrR}t zTrgsE!Ei@HXQ&f==1>dp0NlTU*eh413CW{(ADHmS*3eh^3j!sd!EitbGGTRx)LRJf zn6!V>KMs{c#CU;C!fhllGfH~n^tMNgM=H~kw*p7z(r{X-=IUj%RwkSdI)hjZVNJKv zJU%y$H!9v#_=b^ZJ(6=d6Lq)M-3?Vc{&BU%lS&tf*eu`eazNFU%X`JC zOltu*7rTGVX>T8bYua*{yRxM@2g0El(VKHy-9YrX>94C~9Pe0IAScY*kmDhBI7Qk~ z2I2+u0RuYL9k8(ZzeJOjm|jmXbD&?=#6O1^sLB`l7wa%`*(5s!b5@#S9@v7F<#v^Gy1SE8 z>#k=BA>sHmS#{H?JdH!sIu13+69qS!oPF$*o`B~YcEn`Y0z3$;BaYGEzdU$A47$Wd z5oGuK+$@0rxc&|)+8=r1A9P%Xx;CP%4JoT6(Uf0QlG$Y>to~Ul=w;1v_D6$@f|R~I z#V}hmI|VPiV6&1#^x?3A;i1CL3GD}wf52{!J4F;-n^d3}2Q2kDH|kk1ee&48AB-_N zwsk$$?vh^25eh(1C7$O83K8QNVceDNO}8v^WjA|2n)ANH5lEop94ijxB_`;1ob*%a zE5dJkIZkS!cJ8`!No76NWrD=gGE}#g&pOMK4?;WsEstg3jOaSht6a;|rADl0U5wizSwSi~ zu@6*-mKZ)nqu!u3VU4YrYph!#7O`}>wu(mL%_fX2XELwS;p6kk(b02J2d1u-! zU9lq@IiYx#h;8h`Iw=r0L=Tk8g5BBe&Yf^qe2jQR0b?Q%7|15`w(RM? z_JXFfX<2piZvADiZ$_rzZ~S!rZ?K$SUMzBCi|fodkMxW7(YjYCRk0RE#!W8RIhiNa z4M+B}Rsb)>`9oTNeGtIR)EThWfLu-^$B^smU)LCEX;<{3D!2h+X5nI+OD(YXMQrz+rGumxjApGyA2_QXY_^?zQAuhrty;`cCv|$ zJea#yrKc5bm@{he}XO)d$8QwJ6Aw zw{s6FcN*qjmb~jr$TWx|)wp*k{}xl`_H$(cy%Q~ypkw=S+3jr3aq%aH-b`d03?QmX zY%eWctd3}>P(_)kY9xh@3!|5=XeEvXfmX^=MX3}Aez}~*t){vx4VaY9gR2B!w_Fr- z_M02}G+5w)90%a#f@Zj406?bH49!{TSpt*v!vgs|jMHC>yYQj|h5E=c-O0VYgVw^C zt?Lf1+P!l3se;>)JTE~RkjwT+$NmRnALZR6`e*OibIC}h zx@k4ba04!(+&)*>2;fH5-j~%Q3pQ~?6uofFAhq2rSHz>oKLO>YKbbC-( zqdmsqc9r9f;3T_Jv2_|^_&4Qh#UZlc0ryKXva;Tt6sBr=NqNiMdg=qKEB4N4kU-WP zcrWFz{7}WyqLM+x&qh>dLXtECMHksoMyo1-MFl$S zbkK;A!R~maD3vFLkCk0&@lVVuL9ZWF>q{e#*^r!~zlwwa{?%6yQnG&r^T6T83D|vz zF8~_x8}SLOVv~jFdyyIk6BhO0Pyb!#ZIa zvaw*VNGdf%K{^t+BJASoi+PHA=cz$&B(s3UP+hDV^fH}AkRoQ0PWx$AW!eB(sSnUN z#WgZut2&r@<}!k9jH@(FMGqMalT0wMs6ZuF{!&GqSd=MDrKs*_U5IeqW%S@|WTf{YRQlc-`%C+-8n(&RlVy<~|_1h7UO zB*C#yKgWP%&5K5{{vbps!0VQ@dh;2ExV6Zb*1@4=L9oh1)Y>_Ps_9qhFd&+h)?u3# zj=B+EyB%G1Ze1N1)#EvVd4fkl5@Eb-H19K<22H4^a`XEOBa;CH_oWz68}gt-%#qAe zGX~Ae25qq ztGmnuHJB0;WtmFe$rA7{5t}@BYoRd2*@zOBMX5vbh%|Y0026&^pBZ#k+z#KrHI859 zEWb+m<8Fp&c~r-mVN~;(m0TEC0Na?`x_>?o_jQC3nU+g%u5=nWd*trfoHYYy1DSCX zVJw@$7gzk_cn<7G%E8jOjqN31RtEx`uE0c1Z3v6}VC1+;?P4*P5!5~t3`k8+%B`dE zCBMp9M?N(7IV$4CuL*MVT%O5d^e?qeG@Bo({L*1ng7Ew;tY9Z_OirP62>5lZj_d(Cf&G| z1)Slzxr&gy>!oKQvS(gkO}9lRcWZi9UF2JC$=YgPI|Ud40HD?!$| z6dg9qRl7~lD%0a=O%Hg~iLtG(O@y8{>rYdxR+zu-h*CAidMJKe%BZ)b8iaFF8LR#v z))GQFXVP2O?LkIY*Y~Q5e!7z|+qRpC8&SGQFjTeTIV$3%@|D#ZZS9zHY81qJ&L((? zOd<)VyQrn}AcnkFRgXd2S1Wla*3`K?mED_3CYsO3V4V>@Ousp*u~qwb+YLFTp|#9r z#jntTWzC=xAu9j)@SKN}~jYxq~$yXVQ8l@hE9a@6Kfxs7%K8mKdQc0`SIIq6M?TemaN z#0mP(IYMYb^me55mW6y@cPS+ZkGKCp`L4r69IksEJ}VY!Qzn}SM8(|jH{z-cgaAwR ztzD)3f;r5(l$2dcUU@cb_M4WKzrv)V&AD@i|K!`o0Z|HZfv%zbbC6&L=`!upr36Z2 ztye7_1=Y&eAud4jVa9v~?&v&$Jjsby2^-UjgC>BqLZAsyVWT60j=W+gKn^{sBp1%3 zic5;~xpY*8E|i>{g`c8Bp(ksR9dL4s&tV<4tDs@rv z_{8i%Rknp?a1{UEEDFM>mPS7Q^2CP;wt^CIY=eZ*tNkW62lv?KytxHH!E0(}_B)xx zL2gvU)uvVh1_^*2&-`lL?&Vr|9oG1|uNI!YLK*XfFKV2y=7GCF49hhBnS2#F4rOJ% z;@r@ES89vHQ(zaL24Rn{e_`aeU)2!su2}`wC5FgkO&C5!ps}DL6Oa$7=z$P;;pH!^ z1N6N7ki(7e3`dd8dkl@ z{x*-Q1_qkByt5%txAv?`gWSEVmU&l2(P=R2&gLn|P3kFNL<&en5V8ViBC;a=)7?}u zg5H#1Bzt1FlxxUG*r6>R@n-8G0w~Hs|*1ml!6)E%7e9;j=10RGpqbm?)gtL{{F$(=i(ALTMUTl=s2ys7M!TB zu+p{wu%EY`1|z&q^4)ZJZ1!3*=+36&OY3_Jw;SWpFqG!gf=P=WF@LthrM1K5-fS^? zXVQDSSFBX2;+T?xgmS4a!;InpKSrctFTlMg} ze0m7IfWb?I;J=ock#Wo3==mWhPEOj!@;l`N9} z4TZ34FME6BJ$f?;hDZ%V14h0cG=j6Q143MPa$s09d;QqRo(E6Wct8-B#Vq-O$FjWkTUh27Ovsc)1vhr?Aq>XI>+eImIlJY zs%}tSYs^QT*^jEOq@%@;f>bHNXIHsy>;G&Ltn*f1Zg1IdJMa)JWSPE#>UZ=AyV)!1 z?YT$G1U7)06V0R1%2F2roHu znX}F>vBxNLcQl3^d3eaeklNjaFjMRqwK3-rqAi+Bq_nW%7yEKgqGjBx$cd&4( zME#Vo*;?K`wHI)S-?{&M!068<(=Xytf9+GUkW_EWq~Q1SSRX#kY%y4yZvMvJ_*?wG z2DPqKj6y?U)5$MAnVZnj?i;FnSIqE%EN>uum#y#z*;f64J zt`6fR$PlQ*=v>?))eVk4+~Rc|c$Qd6P{BY3cXTzeeLkWqemr1H%nj9tSwJ*Dq*^*4 zS!OrYbG3Txwdel6d;+=08cn3a4qGeBqW9*Hry4w0hRq3Ot!}_307zK9pms4gpX^WT zzr8r*!`w$-HkMNVTJNSjMOkj5wV;(ncb=$=w`F2Lf@Vgq$6c~R`DuEk?GYTA%QGM| zkH@4@^&i`DSLNG}N!u~gPf265yaoY-GhUT1RV{iHJ>0Q%zGCwnMmrCwE1=rZQtmyo zT6=wTjs_KdIvoT)i_&;apb+oT-M5JinNbC8p!ocPI#g7#i<3s3goc1}?ZDKl(lUCC zlN3}kTJD}IQv^7E98JC+EBq3%Gg>})P>a^W>g+rWJHG)CY$H8*F!J)o<(Q$Zhe~b$ zgBD1hJ{@S1TW?;LN3a1yF=b@qTG#~gl56%{U;!gXpdiC{1`|3`w-B$>DV;`SGSNSK zA9|C%o@Zu`7v-@9*-fn=^dyWK#BVc+YuQ1le6eT;VS<4>mJt2VZVI8`0GT-tj9W8? zfQywo|FvVHHqQ)8T8%_VZ18BldUs|4^Chh$)D()03_=0lzZh|rwU$s5krol315$&Y z8i~pj39)LDc;47l0_SjDQwft?!m*RM1*-@?8 z$0$rQopQFCi(g|}`Y=aRxB{nv`D3g5Ay04Ua zb1JLjrJ3K^W?auUL+W*xWF8+XPVzenSZ%@5K$+BZ^H;D0;VS zLeaaf2?gk7fW7_j_rHA|si$70D0}kciLQuBxxnkU9X1|ygknp_)jd*UBS*4gtTM9= z!?TzHhx1V3VaMtrVEAEPus@Rt2(!cKRriJ?A;t>{72O<^UCw8;3xQqH{L;oD$cA%` zL+&g=~VE>_)1A;zi_oWgMgt*>-<;1ZKru@^xf~#~Y96f+BOBYajv4v`p zxE?;Xicdi@U@37Nz9*TS3@aqiq$^e;d3gI>egd%+g2G)Ldo9c{YQe0MnC7uw!)(Q% zd#mZ_*Hzm600}h2!O~wr^rF!i!WY>i7A&lhjgF3N*`s8TIX}P+xNZEYgq; zEoIFu!aK(x9hMv;GKFepVr5^zdG*&7OID-aXCEW*?AkZZm;H%Ru}MRuSnmZ=QVJNeHcC`F=!99&m~+`DF2{k_Au}oQz7`P9)sU&BQFDxPScu zGqo=%-W7$q@tTEkk&_DQ)0G#zP415?wZGIMqjf{UOgs5!pK^=1?h!c3y0iCSNJ1Gb zR77_&TjCdV!+WVqG9snzh1JCpa>?Q}QgWiILJ06j9V2j#1w z$bfZa?Qw*N_PMN~bwdmgb9(uTie|lis10t-DR)wQ2tL4b){-28>II8Lm@H`>r+RX< z@sRK9wP1H@yOqU>x4G&FK1 z3xt|Hp0n1i?T^QL3N$XH$H3((AGjF`CgM5_Sio6`OI*P9r4~(+i=0Z@b42qeOl+zu zBgqJ=q;#io)#WLD%2GO-_7^FbJSAhTHq8Jnu}W-OT_S$e$2ZHjn`?gXbiK--b0X5(QfbQ~(J?(Q9q}0*@9|j-30a?Y!enuJlM4j+p=i*rS^p?xk$MC zY^B$gjY$h*C?~yjMw5j0gKX?*=SZ zCDpb-Hm-U&Cn?BD7JT&nT+4q8zF{> zYdu?+y&AcNR_k%(cUrWBnynP!B$p%JJ`kGs(JtOFGlG-q0rz=tHn?1SGxlEx<&6$^ z4E7^)eqw=@@-x6uG(%Xi7aGYnMb6MTz{(2zrmLJ(@zynac0GO)BY&&Pc!n99DhhI zb)8rpqVN{D7!6XEqMSeK9Mht+%Ew{iA>d6Kr7;Y=LsoZz`Bm)+hRzmy(D2&Jd`uw*Ta2oZ zMFUr!1Wp~>d6$qGy4qtc2pOpKscVhd<%C(a|UFNgl}=qkG;?g-bhtJz@nEzU;l zAq@%m43>@bK6%r+)@6hPzA4KW=WtOlHe~zCscC~Ijruj(9B$sG*;(6WA3mCYv- zo`%nNHq2M&GM!^~OI^2TH%*Oq9bRfnY0ON*72o{h)E2y4L7(TSv&{(&^Rmu!G-V`p zPPqg9IMj<)36<+ZuZ27UWOI+PR~%ta*2|e{aIzup9=cSivRf1tEqhORf3W1mEidkg zO8DlW;ist}taLH8p0o0#b^EIoQN_%<_#%;WVf3yMMIyfDFZ`enukue*=y{E9sw91t zBp8oe__1!LrFMqNmPk8Fy(yhUyKQ%lT!t~aN8k=D+3U&`B znLisfoJQ!+)U|tjNS&I;Jj`u0V6%|#z3BIhE{jY^sD=^I%tJ(9EbnK>f<8QL2C676 zpo&YB;ju?*qna0b)OzlchB;JuB4#Ha;_#73|EduIw&?H!dhb4VjKg&;DL?5=W7|1t z>!r%;m(NHt6=M&R_sa5fw*iH$qVhSy3B%BglBF-NYR+YF%N)t<^!ws}k8SUSyy=?T zvg@rU1bJl_jYh-@dU#^BJGuV}hf_7EyZ(a*))C=Gh=Z<qXsnpj zmh3yYywZ->)(RDGjVxzxm<4CsT<&c6251_jLvYQ6ZHV}ydq+YA(jIFzjMPvva0>*e z`)L}w;WSVNIPp;A$^%}oK&OFz06~i2QSLB(wc9;Ode-|&4jVz_=y)c%3n{v)5dx3d zqN#Ndv^aVkWlSIx(8wY+3U3=lAVR=xhkW^hb6ne+l%&^Q7`x;(af#H|O3 zfC*PfD%Y%`G^-z^xb&Y1M?2wZA=FKaM@`{Sj)s!4CSZg z7>wETed&1p?s$|fkFEYhb5YuZ&^S^)){@zB{7`%qANS7Yb1??7^-OG1jwlfAGf@(6cGTO(z!S^S_;kuJLdk;ee!PyMNM9Ns_~|w zTG;GZO+hraEwX)7!c}t&zo7G;Y*>S4F5BW>^ae)=W`nP`2SNybeGHWaDA>udMP8D2 z1PeT+3yKg8y0e9#2et5`w>fBAjjnD!kJ(K&(o(NSjPqoKU8Bf#dK$s+xWVuTIIYtK z1b@~nW!L9C{%P%1k;W$MS94_3NEUjqqEsb|tHiRaT;>Fr`c6oDWhR7b>On`WkR57N z+DOxLqH1Is;86cZ!OZcqbze7K7`M=mds!;D%0NSn#(2_ZW7|C#O>QB3%;Y2HDc7S@2fdXMZY+} zt=OA^xN(c}jJn?)P1Pn=+A=S^yoYUrLOkoTxwMhAk4I0VXCx^TRY0_r522oN>q@D5 zY$&qY6*R^p5BTogucmsUtmHG@4*!#s^G+q`D_FZt zF1`p#g4Ci&4wY2`!l-%O1Q$SuymlZ2lNU_G(^~}&0G&EyoElB-%?<%p$-498fnik9 zJUE-prcJajxYYD1(k2KI@?xVuFS@hwfK`D01PlZ0rwet}RLx@%Z=xgy3BKq2*^~RfTgR;6UnfzlnmmabV&~V2mwyt{F z6r}FyRYdK5@jIioPdRtgEB9S!%Mz^CjAZuGW&;_f=-_khNU;2SXUsrlJNkEX-Kg53 zcc>A(*?{7cJ!C@+>40?QY8}Cbu<4yFVvIdK%*eTo`yB5;yBjNU@U6F~Ui@%chX zMFE6%`-^_7+5al(_gl$9^Y9L@rSM8vJEBC2#aRBTx1Xku`Ug!&1_UTao!^>7P*=O!Z+nPTtWkV9i0lf`mj8pjxrkmtC>b&%R{P0p3xLV(JT*&5WT}RbuwZ z?XIp_peMA@{)Pf;4k3dKAgs#*gB~vzNq>2dV$0%}WU0smbbCkt15Ghp4E=ZyLY!s& z#Rw&vqxf&hWiO5X=k;iM`2z~c0MP%uQR) zxrAKIX(?)UNkIRq8wmkRtd3Z_MzbS$^>T3(iy{kSqA%0?aTFG?g6BWTW4nNhy|ddm zV~WrJX1iJ6ch3KV*1^Hu`Tr&UJlrAO8l^HDW4?>IAUv=*dHwhAqG#h-|2<|9ieAzs zV(%Wc2!4d-!$q2keKA~qNEYc)bU9mL4xL3h7yrT0#zthqDD3c#MXZbO~8T ztLZ?d(h;jM!GwwM%eUYC7`;rv`Y8HVCX)Dm)fQB#d2dxWe#*h`!&VGav<$*Dqip=d0wMY`=;jF^c- zt{WWXY&MrkEyS!*(os|BU|Y>8n>yzkB`9W6U@r zZevk;F0++jd?!dxmn;^^ba^Ref?fRW>sQbJBHBEC_TuG>*Z+iEB;UMv{oU6;{1AQf z_gB%===-OyUcY$$HQ9rmyu??YTdf!aX|k&!cri+_qm z&jgg10P-C2m-N%oIb=@~tZ;r=dR?)z1bpi$(Mk?UM$rq%tSPSbnSlQB*>X8Qdie0e zhYx%2rmMZ#;@!hB^_M+7l@LA`U@S)O&X!SA@S9!n*Q4llI!@m$l1cQ#WwuNO`MrGk z{k@%s_xO{-J)_r`Ixtp38nV-S_w2i^xKZCDbt&q2UZxl6w>Z`0+o z(Nh2Vx78TI&;>81OS|CpYCbl@yh?}q=jSqWnNoWbv=9JdPWzri{ z8ZY>EP;a&#Nwql`#?94F+JaEq=2-SPDnj5iSsq9FkGKbYNTc^@I*(*NYL=%egN=J% zA^1MMuXQNRQFm{`BZERM~~;oJP=C;)$C`9%}$7N$tmU zF{`QMMN^XK00}=k1}Hz*h+o6Xz>tve+_F{VSOmEk2>ypf|K+StSIZBODE0WB{jjgC z-%cYH6iyXMOIEj^?MUziQdV}CbNPdg1t#5cyYtytdofGl>_`w!ESjj_Wx$e{8k7frCXh^OI$bQh^ko3Q@@@-P7fM7*3b9XMwC>&qctkt zlolxF^Th!BVkon6SpR3CRu=)`vE<=u>ebJRe4qX`%J1;Z@Qe=`B)Nl9KRQn1Aptn{5(*(db2)Nyr>c#!UnvA zr|jY$Z3FOzThPqyf3gzN!y0g}-8radAOqbdy%%F*{niCWd2N6R+w?wIOchGxj_Bde zmmRB`Ofj8>Z#+f)vz@;qcD~rC+>{`UBukiy|5LHcEx zhQ@;4>LOgMI`evQeIHD7`^I3}qW@ID(Lx%enq`~A8>cvNALp*80b>cQTHUrVHwC?g zPi63BWzSDcQHEXC1$YBv9C|8~Pw65M-t{ly7#6o?TnvjaxhPEJd3;Z~B6za3AZ+-G zpypCP9?3NWbWOP`@I5h<1_5=x^M>*ib3}Omk$ZZ)YM!-#(KvRrZpzWpQi$(fQ2qHoZ7I?6?hdDr)@tAuk&L*?P{A|?6 z41I`vmCvN6Vuy`qAG&xDlKGD`lF(gU8FFJ>g)D6J(h#P!7lZkrk5T6;j2>r1YWcUZ z0Jm5s@AO?;M!!7fjs|62I_YfF2E|L;A*-Eo&biU3sCS2 zhM|jlH-e@fF`(iqrMTsmKr(FXR zomDc>Mqoj~I*5hupun`U@K_ZgO7WygAj@^9741gSjt1h?h%Gt>ffn=yV6{1$;*Xtn zj6FjbYJCDR8qVcLU9lO_kc@MmzTrNMyiH+XZe5y9-MXnpd>@1u7u!p5-)9{3VHx-! z_f%{%7P{?pt?Q22D*Rq#whJ$%9TT`)VPHnTnC+j?R~e(w`C{)T_p81^$k1;@DvGF( zeAMzv?gj)j+~~xCGr<+W)(Tre>1jQ0cE7{jWF){Hl;`5%tDVQpSyu(37huu51>wC` zItgF}?_wt@!+d~X9`uQ^wcz*3Xc~xNZN8g3qko-rxs16sVg?E1WcbCf8_aqkgZUus zsN4+b=;yFNWn=%u{eXUZ6x1H6?dm#`oU?FMTXoLV=27=W_L^9PxN3-BzC&TVi9dfo z19sS^@)VfNq4@c`*%Z5nCLK~r=bXg)bd=H}SxPTb74?f1D|Td#RehquFG^s9pDiCF zCc}H*y2!ZUy+KDun+;a|l=R{JtcEbLyg=IL-@*Ydisr+ME+`=uRz+HMznoFlny*Fu zhQB!_C4>vD3|TE_u5yI`zM76KjKaUTG_*4yb|O=^uvHzd#saK4$tC70BO@7G^f46N zbJ?irADcPS4;Mc84fRwK8AVSIiYZD1zfOQEDV1RVGPSBWd>=m>O0M0 zJ1}m@IB*Z?vQwX^m+rxMI!S#h?h%agp>(Dc@mSZQLa|t=76@ol^- zKZ2!AC}k$;w69K0_?ZYeAmg!wUW%fcgfpQQ>pwtcj-r*9OAxYb9%K;tWrUM4<6)7awHKuic>nS$Z$kS zx<6b_{vSsFM>`Yx?O7sSPmF30PF$s2q)IV8T7uyS9kX~cn-<;7xm5dO#IiYN!mH^q zVrpuXZ>Cd>_6b#jR|pQ|6<3zgkSM_)sTr&JNhR1K9YVA8LT1l1O=7Cm^`|2d;mqpj z2vJP020|>^)>yCB^jLA1Pm!&a5p5tI3w84Kukr^lj?zE=DsK>Mk)s_I#HAMPh*pFQ zx59so2Fo*5OZ<+#@?U>dzrC31-hNa+8&K871(g@IfV-}qlcOx7pbub~d*}M|`}&h- z{|j#I{rUV>##m$jTkmu_p8fBB=g$83OZ>UB|Gl&Sy|e#aXaB1We665WuAMKK`O0TL zxF|%+?l+WuT0SE$R#5gDouH}cM{(~HML(jNNR~ZAE6?sTR29jx7jW>xz3=eT;Z==( zY;-;~I_j5Z`%|;6erYv7wVLXePWw|we`z!iKZ*ZztNqR=@t^tiK>T`erJP+>`qA@O5$PfmoKCfRl@8fg858hWhR*>c9vxjX z(S&;0ck^T33+1J0V6cGsd{6AmcnJ~p0Dvw$=3-Pm{0;Aq6&Bt{P5DMJnkNOFr&AZX z30YfB4!_B{YJdkqh-Jn;4yO|yS9zPJj`=lKZ&Da=Ig6(%XJ!ulIME^uPGv>Z4)RU~n}tr%w8TW_ z!>RuG8Ri;z?JSt|s$kZu+n6?~?VNc(13%uI&RYxy;!Ql&yFqWg`xg`fT!DkyxM_87 zIqROK7fRpBlab}jPj9O$k8czw&HJ?J9#>q8X=xW}^4`|Ws!X~gpN*BzjCO4h?IEB~ z>~3R-Up`~tg6T4@I=q_j1Z$_{n=HQPz#e$sq$pvaEgsL30h-HpGeCiUC^44qs`n~? zNa3f7ms|1)s|ak2{q}@X^oc?jNmZGU8&&X_#n57Qh>Y7ff)>e#|4$u27?27*peP(Z zsylfv@Yn}eflvL+ghcWo#}JNGbFUBaXT&9g)2LwrL-=h%BHjumsF(<=vya=AVmBE8vsrip;sGBAno7V&taEQerP zphAsv*9^X5H{#1MU8InQQ?J}-+hQ2l*URmyV6zrd$_=?EkS}2f+{X5f14`C2#xXcD5SU5(*$bk@XZ*yRxYRpzE%tn8`aJ@r8&a*Vg7s zfL90^lCKY49)rJq+`;$&V1ODW#Qaqd0T-7G`Zf0q4TBkoF+QUZ$YvFBX*BelFU)iR zy+WAsQng(VsGGxs2;OWt*Wd{{oMpikTMMT}DMv^DwtkOI&^(|MAsP#IFiy|YF&A*A zf`F_5rh>!oHlrO`li#gmB*^byz4-3+i|@XTzIpoM<=20fVM{-pfhIS`R`zqflufJm zk7dE`F4nRorT{EnQYy}?oT(#^ILM~*|hn&o=oDAD7G<8M1)k@h3YK@2n4{exP9BbK&)|&X) zP9<6T*T>u)iPqR0L1@*6omwgysWwt+td8!NofeG{=&^KT)NmMu!G-OnY2ei;a3F<$ zE^ahpp#Kd!M0G_#`|%|vlRNf}rloZk(xN}-@Sj@zAiCh&!6->UECzjBu2Lj_iXu<#eO^3iUGOac@%b>tp$u3|-J-!%e*C{=b#Xi4 z|JK<5G!FLLp8Zer;4c2}7x{B%|8r;mb7%i^z4(7B+Fwybz)32wbID7jGBOw>P`d2( zRZyPLOX|}xI5IVUeEAZNl}^hTJ$vq1TH_^6asA#-qxldo17!X`PLqW;J{Mp1WQn>C zQ|8t2IIj*Bn9O1VR^8Tx4iaeysu?D$F&e{r-ve`>O;hmVv2w@QMJ@#Dv#sEws6>=9 zB4k$%eaO!W`~WnQ(R6L|=t)$EL~O&0H}$vfn+9PrrvvE-djjE{;i(3Dz}%qYaUM>M z6YS1O2!D`JE0u}fJZjNRi&`4zh1~WJq@FkcoD=a0@t~WXtZC=9I9b;s2ep7itgt7E z|H|!o>$*K}1$xF!Gf5ZkWMaSoc0aChc6Z`|Z0PmuPh!qIpM9rIn3Z&c&PM28-t*JNS<3_1WZi|SaNs~zDI%=AbKP}eFMw>wnqNR z%jBH|tl`CVqh?L3SzcrLZ!@QpR-lu0UCDo2zB3s4pLLVvx)t`q=BcLWdRMBkjb>|b zSq;nrrGEB0`!_H?-@wo1h(DwRN=OF?qiatm)*!@;x)&5t<0!g_yBB7Ux?2$+QGz&# zFQU^^__iH26rHg_xA_j_&`WetUl))GikRtzrR_#*2&151Mmzwb4TuR-1Nys8JHDv$ zhPem$g*diLg}Au@G}SK-hV;kkJh{m4+zFy1n8%=CfZc}0J{GA=j>cHv1t!vpl~_2k z8O}(EzKf;X0y1s64X%8;`gW1b&x|YymyFBDY}sm2r+pgX+fQ(j4XIdYcqeo7VZvGE zh+EV;fJ)wn=B)iO`1@LfC5o$7FfAE!z|1NXj$oV)#pLjka2(!O$dd-M57RCSjpc@K zko^U>nu<}B4@4KBQ1Os*E745`)9*XG zZSYeTXVzIzY82(c;7ls;R1RLpv)TLAJTGb$^vW2w5^@k1JF4vz9-;74i7rBobDQxK zmlh-Ez>O6WK_t;XgFIq!A-SOBDje)dw=Kz)RDGLw$jfCe5fPK1wal#q315OMic2kN zuk4@jj^dF#%K)3LgEm(RhQ^!1Tm-aXL6Y}$-vRH8El#=}y;}q^*q@DOi_D2;Me+=J zMTXl_6#ty%scsa$25yED{tk@`! zH#KJc(#$|<#7hP44sBMB&<^1-Tnsux3)s9fNGy0uEO=X-JElt-=@5zJu>PZGY^w++ zw^O!mW%|X9HiZ;|V~sLH>D!Ltk*~G9IfaFPuZu28^nN$nOwXeF=k@V9PzpWm+&#n%s#6O-MJo zwu>#V3l1%)lBG0&qO8XbsDh9f;9{J)H6__HAXtPhO(~g6w`>u!kI@c4ChI85IC8QR zLa)0>rtet)NTnZZ&QVq{sQBY={wj5&*wO>tizqm>+2=YXpcEih(|OW=pAKACJQxU+ zAT|7Hkq+S}F_psQSPUUNr*cpK~b#7nVu~h zB!=_Z2Z>cru&hM<)vLl;kZ``Zp)kj=fpXj*EWl0B{sXcB2wD2JazL-i|J)Y8x%MCX zjryJa$Cvmcw*Ob%sH-yCp1?JkGC9l^gV7WW82&=k5Is~seO;r+cx1bfiS(WL<$ZdI z*`d!S-E{CS6`g*X9({Ecefq}{M1T@MjPchA{5?*3>G&xA%j6~e5dC`$7G3Nj{%H#P z_1_cVh~ujW)G?wqjs6{&OHZPI0I&+QY4i^P^w|W0za>K$TaAiZm7{-{y4bu9^`ZK3 zws`M@3YxN`|A|@e7IdURb1T>*#8UyfKq$dA?h2N;SpKOl=TGBd4%Z(M$Nv`d&yHe9 z;3^gXJ5#t37ms7?0vO+)8mbGK{&ljxT_$+ZpBfF>?)*qpWUbv6_f`N9YLW!FCy|6t zNa6G$TlM>YYRDN}aQJmyId`0SN|{$+<~EKsy1u5>gQ}pe(S7ThP@0Qu+4>%cVPYXq zA_}jfmb81s+P%ii3P|E)r~#_ssb~!3{{NDNA$0SLqV@A+F@g*wyAHXZ-wM5l3En_q zXr4DZ;XorA&eaz9Q{6+j*$Ga+rX}o#Kh?bjklVo?%m&5m3AYvvE7Ki&tvq1ZzCnNCpXFh)cMar-%+&^!r^8kiw?vSY+ z8`LyoL&b$%P-8nPcDUP^3XHV~f6|veQ##(fnuFz|JQM3f#kEMQfc5jX<$INW*rdJf zxRtGjAkCgcl?t=%Ad4w0Q!E9OuwNQ9^7oXD71r9zQh~;Sr9f91!Zzp=A(mabZ*=cw zvq50ergFffpLfkI`&l@0PIT|av!0+*YQ+fisc|nbkDgYt9C$-qEv(-uG``Ar$w5xA zJ1C`&DbPGUZ5?stK9$u}@3Ar_wtDAz%C1bGe84V^sGiySnNA?XGg#_jcN=TRgg!(e z^&89nJs8-|vSN^IM_KmSfXQT#k}yVWI6f~R+TtwBsxD0B?VKmcC1iT&iM^!kbEQ4c zRFLpm?*gkbnQoww1rWKo9a7MLfU3XjuBMoov_`)nh>#DAe#MAWm=lbC#{gC*QA_>` z{VdQPqs>YL#}p;|vP33U?66;nKu@9rStgxCF~^v!1=A8>)aCC8z4*OhTC|!_pa5Ix zl9s8`X+uGqRiP3E8s$@+EpWyi%Pe$0SE&^cO&o9M+Ga^{15-P;YIe_ox)_clz3DM= z6YTtRK|$w0K<-=jl{;>(r3V32OkgUHRFY*~74Ox}^nx{}X*$TdNWqrr4?q6PJsL3_ z_RsOzs6Q6NLpc;a2PFZ_1Af`oIev+t-|HW}bZp`(H%+@TR|C^J4m zKNeG$d;B1~B+-Ia_w^60v4Z33kSk-^mOw zSUgUr`XG@$DYje$m0)w2#JFz87E?usCk@wuEU1%Y?p7cl7+nK1)8uyoNj`d)IyIgp z2MJ=vL?P$N!Uor^fOJw^MM$o5xSz;c=4tr3fZ`QyYPZy+vQ`qLN>mL09J6xM#}3O- z?MP!1I%kvi6&>3gf_{^-nzZyMs$%)GBLk+LNts;qZGlcEOtJY*pCzt=p;-Dc$SVU zLm?FV0V@oPlmF{q5(+Dl7~@5l!RXv&rJ9+3k~jpou6P$L4;IejIvn;YOsN)8GWNKw z>D{GHlgbN!F(jroAty0RICw7ON-{^PNiya|P)Xa(vT{fdCp+jGs^=VbA@`du=NUSk z4U+!4f?=$AaaO`BpE|WOe;dLl1C*QoQ6{*CN+!v5#4sNRaIS|7CRCN8A4?xky96*4 z+99g5Sa(}h=@Mhvmn_g309HV$zZYw4$zuEgd=*sMEGt9tmBBeI!g;z-7gKh{*{1ta z=G(ByPUQjyNZR6fW12Lnh_b4`-m;%AnbzD|ch~NWZP}sVX>0S>dH$bs3MpvgD*9mJw8sW(b|?gE2zv?)^2 zqp#4KJB-jcj*Ccar^O`r$&_J~k2F?0#Og8L&etUAScYJ(uST?$2($NLxtXL)EjPbI z<=isF*%@g`)r>_1R_Z}lfb=p41_jBu*!o|0o{o_)y5OJSWz?3rw2k=0@(!wRC~Sgq zFYpc9Q4pxSD$rc!3iLk8?HU|HA-Ai=QGX-)l}Q>j^jo|%c^wez-?;5rnher4Luy5x z-Ly9wTwbf868gL7fVdgcE9w#?_s`HJI=tUTkH};u>GEtAI)zHMN3e1`2?5o|1H70F z^ki}OZqzY(Fw7QxBMS!lN2Y+6uQ2F=Hgv$|&()k;U}xN4H^p1+OdJ(m3iY)N(MEA& zYKXVhGSm>F1i>cK8}(ph{Jec^uXt`3H=t+g;PVi)RGnOVa;m+!X7!USbX>ZSInJw) zY_}F^A2#Jng z&|#+B1RA9gC1XUi->!ArD)@v{ zY1_E;*Ba8+k20{mTY-H;`N3U1q|%9q{hBQ|aeS6{mTnK8-Zj9vw>^4eIh7ATTAM4R z`x#sSmZ{bOPv-C#VeUnwVu#{>N*b8_TjT_^A&acA5=rc#YIJ?n-ywERxQa^Ty|#*Z z_`)FTLAd70$bwLKR4fC=om6KFPulfw3$m8`0%(>!Y($ zealsp1s~NVlC9U%vypbh3Rh;gpTR)Bg*vZqqR`Zut(M{jCo6_7BkR-|ycfU>gwD(L zyEeJSp_&XKv>46EFaW7A8INZlNX(h0?*ht7cR<+3v*Go|&FNMQoGeG@@}8C~-mNC6 zyeii{yI3c1HN`7(9IWX^Koa!@`F6prxS*L-@`YNP+dd$r)SwuKw<82ksuAR^-F>Jix`PmE ztn1nu2nyt7t24Y+lht$0hsuhTqk)dt%YwROt{CC-fV)Y-*VYyYyjCP{j4dDE9wowHmFK*J&<~yAJ_K!_@jG!d^R_a>-cwE$FJkX z6was-*>?-tNFtRWIlbtob1Da*`q}~HY&I5zmqqUc=+Rt|9z@#}#DV=SXVG{xeJ`5~ zQkc_xwxAaZoF8nM#SHyMa1K!O@AGu}!w)Y-Q|X|h(KQhaCz|!r%Qct*(n&BSF2KLc za0#G*Q!E068T~L&E|Az%jlBoBgZ(Er7;Nr1t11`;)Yucl3RX@oWgKp*qdx;8a6_oA zBSDbe)*?;E&<$)mNUApzQ+k)cP7uupGr<`&SmHOR@j+}{{Sj<=KtC9Q5B*2bI6yF& z*~9|Ibjq5CT4I;j98f748cZQmTU9P4(g>_THdCF7tt)VxUdMk(Cw~~}><_$bl1xYQ z;ye<4RbuV008bYz5quC!pkFN6`)OJsgOjU! zUy+}Tff`~UJ5#u*MPG^ky4`PHy!^V`g`Zx&_)h#(y?2jUHuYA+AtYGBNtqa8@Zdn7 z-n8JY1!fXT3)*U0DM59+H|@95rVfW0#!y&`D*w0Myr|Sv*Q2*pW_i~K9xkQ|AJt5) z)V9>BEAz_*K;Ds6)YXP!;7fyf2p$Dc^7Rw_fKyYw(QLK%I|ql4o<4j2=dZu1xM~=| zVPZ%!OIES>f2!X{z!4*SD25rd-Q~EUl-#0%p8T;iC(7PH-=nwUn*iudA7X;?ce@FHH&Xb!*@3^40haXeZ>%%K@?Hb}-fxz9MyX%a zaf|`>a+tv1oi_Y^fW0>laU|@0AA9dS!unXJ*V$x@6#wqDuy>rzKF%h^ep^`5#!-g{ zRDOj)UpSr?!~VfR`>;!QaD}ORG|Z!YXx7K646y4*G!+~m#i=~1o5>v{28}7!+$V(7 zPi}Z@i{Jf4n&5{qlb}XztZyqSBfLTSVq6G#^GZt2q0%s^Qda3^vw)&bqn`bah$Sm7Go^qQ%!UlGCwAQpD{* z+}Ido)zM|Bqhf%=9bJSvx+v_(kbb!S)=3zms@qu29ySm|M!4RkUGEa>SrsLl4+C{_ zB0pQ3N$u`I+V9eN{;Be)**s`BAJv=tph;=8_aD^{4i1{lmO$5jeZP6o*{^pxLM~|T zKRRgbKcZhd4G6ojf3V+Z)f=5hkD&6SgUXdZo6uTm=t3}h$5#O8c4z;fdAQ%+KNOJG z8|_E+mJnN7^?H5(uu-ocib)7~>#b%>RP2aJ?04FtM(eQE>9ijmHkya^Ljm`G{qRw< zO;8&eZ~8ROBDeZ;(@WaSUDAfVrcJh{Q9#y&LsZl7MBEM1r4$>*Q7I#1+uf6x)1A-2 zlNPF01KUzC8z~OS4Pc9r*vun;=0_;;(~|fRXP`Z1P1JK>^9r`qocfcwY{UgEoSrwo zR@tr7R9k`L`69Psa6$A$mz;SE#tq!M7A@B@=_TVZ%Q9@50T!$;Kzw8l4N=GD!n6Pa zEn(moGqxcs!;US`LJc%*_}z&`?6m&JKe_DCOR`kLUKO8$4f5-Us^@nf?ESxUtN*u! z?Pd_$LKIns*}~E=f*eFO3lY_nh*CHMM|&(ag}TgC{HFzTD+qH7D8wCGHEHKIk<%;$ zx)lVv6#%;B0c~~E4tCTIbkue_x`$6oufBN>*Ae6@5pfkQZbhX}#lyqH*5ST5?;4H6 z)}!X5!$3;t15*S)x8di8`UW{9MR9}v zY1*)_gakYnCAR1vuWIskfm;e-S62j_@b?Z=g-&YGG{Cr4@%Nftt@h+0wNB8Rsut6- zEmrZ=j5Gb--@5r7}{0Pw9lxFHoPz`ETm{UO5hTvg(;WK8dS3 zUgsa7Dq)|g75e!1AztU3c-c>T@(K@{4ARB)%IQXWsI++0G}@LPss`!@MrCk_<@KRa zNc0spE{$zQLWP7H(INMp42pLG88p!PzMNi zt7mjKguDj+oDkZEG{b!4kz=KUyupD%&m&rIMB!o6ptGKs6&&Ea+6c-p-DpMwBB4h{ z8%4y{BElo3T*Ij8hD0DlM5R=IdZ;EgZ6d4*BBoAyOr|;`8Yd9;8}zk+@~{n8lS3>ajb^8( z#uzju`+yqQ`w-hmy(X6TNY&gnP}AbH8wSINMDe(o4eX)bBQ54Sw$XHSx3oNVs6uX1}|$CIvs?wLdTz?a;cD^1Wf!oiLM-1{rG(>Sj~5>TD&o#=4HZ zG&%-r4eX1!Z;KrPL{Iy~vvH1(8ixMbOn**$L~QGVSx?d|OWvi;H;Tj2{y%J%*xOBK zZxcQUngPy)j#@g7^i2@)-f!_RT61W!Dv66`uNL4^#Vuc7NOKXKF83p6H@u z@Ifq`o>GXB_Z42{7__28qG_tf)|J+1$hZ@oC>dM5VG z5-VD9{1MiO3&HRiVpbg?I$4h%pTZFu zBybqd1<709|DU}#?T+e5)`jn9|B7n8>vT(v5IGNE`!0;JO?$uwJhhLTnvKNWbSn0YUW=Yy z%eU#Z{Im30F7GvQ!F#}}Cj_g5c|t6RmDreUzNxp&*Vko>30*=`>5U22 zK02%U<1*j2@w_#DecTm(LPMO^6@H$s@QZbYpWT)75}J3d<7X3^pPSJ9?WJQ%vuXP# z(?fLm$Fc}0x*=~S&ZoO0Ll6v zU}^l-+DeFN1yoy(BsM1b&mPTbO-7wZcF?hzPRL&e{~FEc&SQ*_5kJFv^_s7F(hbf-y9KK=m^V9b*AD7XpX$DZ zMxC&QbR6Q$3d~Y^KS3H$yW5v=fDS$R^7A{b#KU13?CzBDzD3%RFxc8{vA74DXc^Uq z#2b*Kc4`V$HgC;m>R%tsLk0d825MZwM`t0rl{>RtUzU94^&*RpW;Dk5WJ$NCAZ50g zzV-^<-`>+P-uWTjTdeqX$M0WJT`@2 zhpnv=;^x-o!Esk=MyXT(XgJz@wsUj4OWAfY)wXZ4Z33h1i7B<~jh}5DZwzSDQadSl zw>yQlZ3An!y^~#g+?@tAq}QXJbknLf+WyH$pWPdfZC=N(?q(dlAvP>+a-BSJ=-LW; z@}}$DA#I+2SZSWVb&_}2cdT>=tJ0HS+9_=-B#oc%?;h^8WWO|8{4pZ*3T(`jLhVW0 zD$uA>x_vNhlvbvz$&`mKE2lJKyd2tI?7e9DY*v{STMgGT7$1#LB5EN*jHMW-YYs{Y zR-Kb7a^{kZITUGpsap9OX6qVuMTVSJjE*yDosOaUkhD}nyW&EqMps>V$Wfz&Ds$x? ziCKu=`J}Q@akfZ0dtk~-Kq=pb&Ha_p`#0+|l=-xyhAIVyY+ka zu!_%~?Cl+Fez*Vq=I_>SKd<7&ch7D-_~xto4_;Yu_|2Z>kL&J7|Gm=+x&O_lC(E5S zWS%&XteID1PWxp-%PHH?`}80;Mw|^iSfTqiATh1XmANmqJ#()hYFV+|-gkz;h7i!2{ zAaw!fMsIkm$j?Fg1b%hgXINHeJc@`Z7S8-t(@9>CPMUTBNUN4p%O;F76Q&AZxC$X= zrhQ;l<@DkSYSmklAR9$S$#W?T48#-oB6;Cb z5zO-dU8fz0p$n0wB+n`s#uZP>*d-0UjfYYA#4PtZWZ@JEEjTu17ECSR;FK)b3c||` za~Z`mebw~R7o?ZuQb^h}!X#TxF$_F(j~5CyBkBY(EF#HZE0bU+rg`+K5>l;PFk2HO zi^r6_OTzI4b;lB)i9F(@&{ubN`! zf)rytpFXW`G_-S#4r&K1lDJSg<(eFTy;O;NY4BRsB%qEwq|-oTW#GzbQ?w`s+R%9J z@U(i(AbC7zmlewiqb8J1SxJnFR!L;zO7&JjS!U2K!3tb8_3Q5b6x@i0p+kPgwQ-YSs0`rHVL*j`D}x7u<6zo$6~HfE5*ZpdkmrxC`Lvb zB}}+5EC9+uKQO3N6=B>UHC!3N1C&l(rQRPRo@LHX``CW4dwE3c_pdIEi0`P=-t}`0MC^CD-Wwvm|AwXC z^Lk&1_$M$d{ch2FL&W#ru=M*Z?++2*cf%sC-eY-JPI}kRH4yRYJ(hPS;(Kpc#MOH& z?@Gk?->`_Q_gLPUi0{2&5m)cAygL!!d&6?|9?QED;dCOO{kaArUcJZi&P06w4a?Pg zEbmIhKY?MndXMFuiTM5-maF$z-kpf=mjCLBDEmE@vb}dO6B76~aV^)-{!^TVLA&l? z=h?p_BIg=XUN%Z2RbJ~C71Sn zBTsHxIz2z_5>cCKJvM##iqajL$P|h0$8NN_%7QiYKRva$XC- zO$-6gLd67J%B-%BF_Pqhr56HAhGBZgk}DMn|8DkQMC4Wyu=k z^js7l+a@iIqO4;j6k#%lK(oNP$h>%)MF~i37{=xE=Gj^!OU*~BPI)I4SH za?Vjm9duPtwlSA%Lgh{c?K1Nz6)zl|N+l~~-FVJjVAlYSRKFWEM@RQ={HSeyC%Mi- z+MI(2s~OEWEJ{FX9h_Fthn%1xt5jAn$0Uq=ltNXJz`d;MaLV?8%cEnz7c{RQ&ASpZ zasBp$G?5z{V@@nPJV;P~P=~bP3)FJfRB4%anuiFvrVXFQE0&T2UuqEf8r&b%@BYjY zQof_5X_C#~nvk|;5t7XTpsCgh`7M#lDgw(UIw(xVQ{+KI{K2ZCO8kmq=t{FaIkdC9^0_r)d zfr}Kp!d!~6E=0vRPp54$zC1#n*Q*g%M9IdI?rchWJfXXvoUJv&Zrdo}rGrvRhf))R z>2|rI8g98)aoV*ic!1Btf>1#4XjK0}0hdR~b9y#HT_sPRPDu}*EE+aHNTtDyS_wy6 z-7OSil1|jXS%zyx1Q4R&b+$#i=xBaSaGapVPMy>YcrtckvQ~kzT`q=#)(c z=SiaqiF47cR%@k*G%o~q5ZIk-ny%oUg=iRas8n7HCC};I2z{9t=%SQlkxmK7G6xnk z9pU5QD~YOo@|8|_sFK%UjFKuV7ag}W1?gFes?^}3z7~sfPWJ|4@^7RhTo@41mYPW$ z=1?Q!nr1AdsD(=-xewk7*rFsAuM)gjLh&|1v*NYB7Cm`R|3+y2Z=@u!p|GLkDzvY( zHy;KkSnUI#5HrFUEx3halNt9Mo{)3+hvwE`#jVcjl%ql}jgqF{!Flx2N9=70_ill& zj1?ALvDUJzd9s0yvjCZxNg7y^X3vzYG^dL%wkQc%PMo_0OJjIR*8zG=ze6*sLm{XGR-Uy9lrkPLg*KYX-N#1|(pSq#dgSqiZN26-$9m$H>(|s;wk;GFE0= zBt)=y@{_eQDFT7J1ak~eu$EY|vNlBzzz95Eq_;E|sqh07*220PExU%`Ak**0v|}P^ z)o^>}EXu*ZBldz80aZ*zI!UM1SW{g!Rl~TzeaT*)zE;TJ+O3{>I_Nu_b0*CNsNV1L zygyV2BJzq8g!Hf`0%`$rZUG%j1lK|`PNlkd52@bo9=$(Q7o~8Kigs`+tIxFxqqR{+ zMOgNb#pzU6?;+LuU8(nn>IKdaQ@~lgSOvVM64Z*yBGDOE2EIu+jq2__q38n_w^02()Hk-@5qy8BZtS0p>L1KL8I8e}9*iCU zK177mXMsDa2qAebqh<`|&}ZO5tplUe85K7HMp1Lgy>f7LoJ>K@hLepCMrT3DAQ-d4 zc`l?4fjPh#4Jva$ORnH*+V($;pyd)3u;xofw>=nr_wlQJBh&Uz z$G;D^o*aC4@5$r5^~n$6t`RRj`+fiW@1K1B{j-PLpB}$>b$th;+sio_T{CT@&{>42 z6pK}|7%QumTM*F)h^H#1#>6~Nl|1a2OsdX;0c7@G)S3i0$>{>I)sZH!W3mO_a`9~~ zFxqO04vE#8lMvb01c7!cR0nsyfBxpO&d9y2qtTV)&_uB+X;ik+IH9Z-PE^fpkm#S5 zE}`2Iy2ywE+R5zD@fub2ENJcFr zn&|E$Wr13Ssnt1C{450BXJKNN?&^>FwwHf8IyfwLhX>c-;BZ?Ai-4Vg87Qi951uL% zR0Lv{!oYtjfnYVE=bCo@abJX>ZSSUVC_9>V<}iFo7+EBbEGC#4ZLCb(8&FRbRs)Fd z;DB<_{>n*qwa24ZgYG3}j7`>g3q|grh77s}z-3qg$HiQHieODqpu1=ewLpPukI|f1q&JQVECee$%@MrDkC~3Q=+5r87soFLZ_8@Xc?>M z0vwH`Kv@FJE`q9p)mUuQl@1dRp$b`;yYhkh-*P~D2@V>CD>CcSiee4nfRYNt20ltj zT6k+5yqqFn9evCRAR2mGT1XTxyc&^tfGgvw1lX$5MyM{AlF1ov5}HW6m?3j2n*>0N zvDCn7DF9Vn!-XLBdQM1(`hfj{;|SLq>RN&5Q1BQ!410xt;FDuIIa2t!YE?AoAz|B~ zzyScj7!h_aYgY@;1vUWG&2SY95UJAmVT>?P=(T7T2$fY1ccU`reTg}rvX*mRGG4nc zn5_=LP#pM)147sg5Lv-<6yn6J46GDxAs0CW1F_MBKzT3#Va#gImtB(Ov*D5ZT!7nk zfVB$__@XK=N)ibQNhzN+%mA>f@f_wrMxbB-mOy*#ugDj?w2r>5FUa}tKi~cN%cFby z^@qo|?33dkzx(3hGy6Qf{5I@ue!aE->OlzKrZ2vKbd8r}x&A4gydUbp&EIy1r4EO? zJ2y+t!*FwSTi#73ZV%|rw*g-+zddS>mN_swNg4)AFFbRmfG42CiW3fu;>eLH5&lp1 zR%KdjWkw63JQS9Ob#YE`;DsQGX#f;xS(VW}Kv4mY3Jo*?N%wRcmw@Tg912^yVgtVn z;Bf8oNej#zI0=|aI+zkKXw5i)G(6e@-za$p0#?YD@&@{zrL0LWLEwyG%jRknj5?!u zWLK*KAz!!%LU!@KavY>Ks37$CJgysS~`m2%8OY7*{%ICM=-~H*; zjpv_k{_y+bgIB-rJb83*mwbxl z@@d6#2?ZKr%mWoL_&l^ZKmg7I;{m!*lmjEIL;;<&&x-E2i_((a1mpl0(Y8~kL*hlr z0x9*TC>T=-IG2U$2;7KT%q z3}6I2=Zm$nDj+75r>z8F_8~_>ED39!ybK&RoJ9eafv=_=?Q}_|1T6vo92%>X6i$F& zHJC*4(k6ekg3J*#bG4_ zB+jY=(bp1!Mw6T@k|~F|B-@RF$$-7uXGI_@dkqy|JSZAEW$ZO{b#);JP)|!yPzK!r zSEB%(W3a5yp>*(?yed2h;cZAUM(ML=qGF6NzH|v?Dgq?Ug$@Rxo!f%0PUM_oV0rK% zWW%hd(=cc&XvUD`Hkaanz#|NVfFoc@e{fkdEvZ`OT(%B9aZV;@(FGb+^k0MLEFD>5 z9T8ju%Ai>5ierIcpn`#BjA(&HcZ^pK9vgvt7AuAUec{=Ymr`ic086!qT)7F<0v)p# zIYVnj2JgHu&oK-Npny4D3=joaS{p2v zTmfOZWN9sl=Freo2)6((B?)DmIA2r-p_6nVi_XxWA?GYnEpRapg;}RG50n~z4MaBz&u2xZaFc|QyfNw!r zJV~P?J&`L?0Dx_cmYRHL{mMiU{>L{+8wn_!`gc}9z zNkQ8I;E3*P=ar%sfOHEjYs1k2FsfEq2)p7w(SmIXuJGuk4@LQ+XvqT19KF$o(-tE~ zv*gJ|^w=?^w2^lG(!G}6WvEfcdCejN8yILZFh3k_EeKkH2CPWtAlOP+Xu^=td(hq( zXCfLVpc-LdXzO-@vX|Kd_XTL23VM6!A08BJgYq=JTj5Q!A`)~yv;i1S0Dc&1r2&Q~ zCpw^?6+ICOqXB)$jr4H+@rwsT`*tFO^7qj5mZnol!HQ&SrR^+0IWSZvqHC~b&_Ff` zp(7Xx>PUmybf^IYmNS^S07K-#2-#zNGx{Hbr`vLMsazVb75axEr~s?bc!qYj!M-3h zls*?Ng1|`dUsaWi9eBVn<7sxDW%4EiB+L?Tk~Ssn2(HbN8Oy-?Iq_PdnqXNA?Z8IY zat+Cu5TTt@Te+j_+AV(2ZLcn)Wne*2BGRR?Fe9F60Ah$Qhg`7e73^)mzqxN~O91mA z7w{QOZV@WmlxdnmN&o{HoP~w}>tJj#K45P23G$!_IwZJtp;0h$&0M9KXW@XpgOEu{ z&=3q-pcXQ1Km|Miwg}W7Zy}Y$%BP$Q^WFkbLm%*>_+5aGlf8{V@@b!cN}Z9#Bbx8aB7+l;)l}XP^N=TZsXrWbgv=6g6Niuy=%_ zmb%(NVS@#ZGYkoAHIN%{u5cO(-rzmVW3gm<0pNjoX#L1QJ9C>|J4ogpwo=}+qfSxv}CY1~P z9S?Yhai+VJ3&tSv1ZUV{oIrflP|y{5>6g{fw^agPZhx}xclN(XU;q5YT{XP>-FKhA z{zn1gD7T(`_kqK6Wes=7eSL4+JYi5uObH$h8Hjt zhz`A!@I*X$NfwsC7!R)uXu(GhkAmPnC~aX00D6FjA-oKBT02e=KR_WC0|M*>fNv5l zs>7T^;$nrtw-TaUYw1?j%I*bq%Tk_P=WKv^M!-ry410p%VEI2|yvT*E3;@Y_Y6v`|ujEW%V z1Be{iW8?|?5rxp1HShvV3W7xjRix+)765pfsDQtTFL2c0q`=JqYJ+0|>j?0pG+bE* z7Z{Ee{B{R^bPnzgolghPv1Sd2!V_jK&}$wjxMCb=H?vc|c_Nx78NmD$0|^vm3$S|N z@PnKr_bXevzMNXhysYF92l%ZlSUk%Vh(VKT7)|sV@(Z418$^Fv1y7whExA1IWMn3+-Kh0NGMm?3o;c^nj>};x?T!N*FlQ@ai+j zuc2&3O>_(m9rWY%azYD7v9mChQNeM#r#YopmQA493u z1p#ams*j9 zqJH9jeDK95(fAv$j$Xg`eeZMo^OxE_dh+74``2hi`(qcENp8>LQ_4bca-?a7%~T_j z2lNF+~IwnoR_9VsuX9Tpc7Vv5nz!fhZ z)OqBA=odoTx83wXh>3Kb;<=g8r90Ol}Po@TqDpkYB|Ei`9BRvpX-tD`;8 zdddZs)~8J2jxG2NqO2T@cA)THI$$wrJNjRW8;3J!gOjOTnWt(Mi;B zzl4D5pjnLNL`?$Dkk`;2bP^%FV_=1L5>yVfD+Kw7gG5CUR)$ib-yJLfQ^i%FnglhZ zJUQ>QuF}H&VcLP@XePJ-{Bt^>4~PjaRi+R>2av#ZW^^KP%$E@Nzo6-t>>|C|NFgvU z?VB@RX1JzsVr^B@IY8Z{D9R1yw(UK5qpq30* zg%{_Yj^uFCiw^OXZNCb;Xi%6f1|R8 z55%LRueV-&w|(oYo!|bs_3FmUpa1#Y-G3Z@^3#LsT;uGIuw5pzJ%FtwodAMZ-(IE+ zjYM-(0QG?6#>ZMP@J<5D!)+BYz{Vyz6UqWd*$idpW1Crq=w{9V+Tel-fLLJKLi;ow zw*p@nd=+7J2_nEZD-7doV7pyAqBOuq3(T0)PO`rw&F4=!>u3oT^>QjISOd5v6rEF) z6LcP%1zw82N}7JuwZJD;0gh!2#?zrY67HT2%W1ACwwt!HT0k1XBy=Mrz|sVF;U11y zkU%-GpQx~fryJ|>nsea_EgHh27DcC)Ds2@U5>@DgJ=z{roV9e!Yo-tqnw6~ZwlqLB zAfA9w`DYU%V`cD4y;BCmEbloDEvp*(^$0Bgg)T48_p>vzFOJC+t6`9 z9i{^Jko#Sd=fPB3!NAZZPX2?6V0k!s(SVUDLYzf-m(WDcTMk_84MpKNN!|%8IGk~5 znY0mhtfoK<(kjRV;8ItcZD5dtYuGH|`y-W>PO|n`b#MjjDP49(HzdGYr(?l& z1peW)P?s`1Z`fPQVY8hJPzecmMuMy0atAuNm61@xUk5BOtn_XKug(~n8+9pWTF9;y zK1c;1N|h8pfRJI@dWDu4_-ht;N@Z&k?dQe=&mDJUHqaiH14NDm<0OU6nUdj`BYBca zR}GX4yAXkGV?fE>MDdkxYxDg1{-Rfl-8BPWUV>SHdaQfZa}Xp zIk@{k@>SBYfThr4yP@y`(mBA!f;@>pn_vuQRsr8AmIO`KSL<0S+<~oBf@X|DN1CO& z4ym}{(nF8R4}CkZ0{qfUt9;4QT%8l35EO4|$IJrH8t*~^8U<_0kP^g4F_s}dEznk77tE8p1TFE(k*{c`eg zIu5^t8dQRkfX^r3OM01<@lYjD+a@bbTg9WIO`AMGvS}?3Tta`7&x)o%YZTB$D2G>V z65+tS81z3G7?ldG9m9nn=t#$3ftQtXTF^Rr?v5%*)!%2m{ z04px0ob0{AXps<05K>a)W36z6K~PKc))`=(rd#1rK-w)FK@4q4Ktr?&is6L@(19Vf z*K}H@%elgZAa9*eyN_ORNCutwU!d7B5{YY?T}ma`8u>No>x)gSh#s5*uIZUopy&<2 z+#nT08c{Q#GNB1l>k6K9j_`wF%UnBWkkR6{mOdm64B}GJ4ePm3yoSO7v7j<&xe>|% ze5#G)6hy#VSVeXLSltE;jRYxyYS<;SfU zR-dGhkydcv>`Ra&!gqDcq6VNgco8BSZc?N(=YumII3}vd;p4>U@f&+-(Zv!85!uRdox2M@oy|9t<6`Tp~7e+)a1hE=~het7iY z*|&Ee$}iP{y2hvhf3ayQvs@q<;1RGT6n@c;<}2GA6@wLlzvMNS@KLKuqv1Knr^0A_=(BC48s&y$uZGXhP} zezHglD^%bU!$b>C+uta}3uyJvxG^vRed|a&k6|v2N?HhlAi`^kA{Q{$Il~%TI?x>M zFKH0k;um9}(>&&!yRq&=7D3y*tbwWKw!(}6vlb5fUpxcx$%qGdS`=pk-$^>ya}jA3 z4bV1U(Z;|_>*(9+zSn*)ZvGSS z-Mv2D2f|!PB<*sEJZrvB!m7dgz&~L|cn3t5D}~@g>Nu!Qfpr8zxBxeV2ydS@2xQWs zFmri3z4zM zeKB+p1cR2Qeaevs7F2Z^K7#eu7twPKu%Z}FU||3~Nf!^$Ds+|HNZ5}A;0sLQf~3pj zxv^3xTAjAE_GVm^Nt+7bRs)54GrEG!$x?wxd~%kya7HLd7B$*~qG8tz#r@M%hwAo{ zT>ZgNoLz9nsmE*tbR;P0z;T`{PUpE7%~~Wxv~)8Ad=xkiwEid@2LSc}LDp0uTc~!T z%TNWy^azT(%MRqQuHj+l6U?umSdAV5;03l^s9NZv4fum0!f~WnY5)U82W((O677lc zzz>EN_2AA3NfRcL&X~@o>(BV;mPKEP{MM*d7L@+Ikxdz(e(q#$2 zy?CDdWT7?CtVqZuWly1+Fzr!;gmk_M+(Obpmg7aJ7yzCl%z)IvkZPiXm;!vngwaF2 zNzqaRocAp0$eRd99K#h%$O)i}j-ZHi>t>+y9w^jF6H2%S^>e}5ryi#=kO%D{1L%_!W?T&%z6)yokc>t=Cw9ON2NfWJYgG0~SthW?t!>W@JKo%+| z22xt^O2OES!k98BUzuaH3@Z}t4s(enifMz4BBzt0uPD??7dlWyknGa(1YG*eY~?_H z-qH34TU86)HYv3$!0MmUHKmX~(9_dhxZddiqC-2;q3UqmD?lv9iMExb8Vi&b2v?K^ zNjUlBRhuR7%+ijhL{6QPfIpco>2tKvgLb58Zy+8;1N+dOBJc%cQ9`QBgU>0HDz9iY z_R>1~w(#uxy%+yHPUY_QXTRV7;{KN=e)8;Fckoa15Apijmz&SNd-m{=IXK$mzww{1 z6P{ggUbH6;2Z9WA1e4{2bwV31E15h}oq4&a!m)&YRoT#Knu7LR()Ec5M zt0m}oCE+h2VD3zndBKUzo^_MHY0RPmlv4$ftD?=PLMLvz4U}3I3W>55m+6zJE{Gx{ zg)c?gr%4mhg;o!X5OD4@T_;ZaPfLWR#NZVh0aa>M(1Tvas%b3{1L+IICvw_s#V^6+ zT)V1+Q$Tx4wM~}7!5kby!+>cDb94lO2NNbn8z+HD4NXs4ZKM&jr4YC_EeklTig9=s zfVUAA9a)QyF1r}4R|YH#aK&N%y#XAgje8a(#1r6dXdNN1$P>M^j=rs`d$9H8YyQ&_ zJHEB)9zB!y)PpbYm&d`~-E{x>UF`4uz<(BB-eQmb>8>&0kh6eR%uxK#`Ll2cirv#x=+67poWTi)tLv33KDSC|NXNBYxMx7n)ZC13M znRcYxYUqThDnzz1McON@0cB|;4In(+Q&Xb?i1)Pb-oj1xJ^<_#cxKv0L5CL6$r>=Z zNqPe-3s)qocB|~wE5Zv#>GhZxSm~VUOqVL)Iwn_5%uX<`bfsBGtqQc4Ta56Ys7nTD zNbz&h(jBfE7+Pvi!NHspQYjSB=;0S-oh$7rQ1qM5Ml^J~NTr=kaFD8{=xs;wk_KJ@ zo!MuC*0g!TSOX#_<_So6W}rMHoHl85ihsskPVhIZg|ed4H#HqGC}}@M1R74{+|!m+ zPfHD?-e_l#V5q?uSPbuBq?avPNIJyZ=zW?2gpMEOeyneucv~^ft9ewiZA79-4$K$Q-PhLIv z?E4?Xlf!?0`QjQEEjYW_TsrTWx$8lH!Z9Umv7Dkbs`6R2BP>DuWKy6A4LavCYGZQ< zG)t1;OcdKT#tA`DoguOsoPn106zOAWvz%|!Mn00m4Rt92Ea7ORL;(#pL*NUY@S!dt zGWq%)HAN>J(21~`?p@4K-?A9NXp5d_E|!|0a@x5V0*IQ<6M+B1pz2*A?p`*Jo@j+u z(lyw$na7)&Bt;WEw&#V zKlF7Gq3%}Sr`r=&fG}gTk z-Gqyxa=U2#r$Hwf#>>-*F41!gfO0&MPBe6Ku*n6=kWQ6}beW~q$uU}#1o%}+(>?Pj zAGXlbxetN>RzRu0djagJ1mj8qC^1(=g14chrh5wE^8vDC=OrDI<6}|D{uvJj5Cov< zTw_H?`DO_PC5#e?D?>u41r zc_w|ZK}os|jDpxuvDKPRaL|GPNuX^B!2SHHoQuoq=vzA%;!AV%=*bT^4!%}*x4%2w z(!1r^fj&HV`MG;3_Tty~-Tv_2Vfo?KHAb~_ezEl#(YMY8H3ni;GHV!KlXr~%l_=$8#dZn2yB@(o}Rz6lq zD>9l@c!L~L$ORo?LNnIVrbO@;1-a<7%XB71(h*LJs418rDgK(yhhVCSH;Mw!_AoAGQYH9>%TBgnCoi8J0mnv+2q3 zIo(j+l}9;0qsBZQHD>VHE-DBIo4Y&fgR+VD`-7Kde~8}$F|KP=;`(5Bzm>8Y4yX_N zgWWyKxQ2!w54OU=H1C-dnRdKgx=gh^-`ztWpQCK_`qd^~&0GeD!%`2oIyHpUgC8F} z`QqXCPX>3t`FZf;-A9k^e)Ht#J4k)-d>3!a%hHv#xxKeV7qg>_`(fwc7(Ho4e0~4X zy)TgG?k5kvdhq0DbZGF|gD2nIfBbmx*~3SJyMu4)t-uGYKeFTH_=-Y>n?{5qS zj|(-dv=Yvydu>Aq(&lmiYcd?s;%5x{5Ut$GgXiI8!QiK|`4VjmgS5MMeC}~=g@vu% zooB7veJnW`Jg9@6-GlYP5Uv04`N6^7?OV5Ay?V9rZ0B%ecmLU~t**S`t&c}7yoYA& zZ$5i|FaQ>`H}S_0o|LWfY(H!d9v=@63fS+fufF}@@3%hq|2B8h)?qHNq@9i&tHtH;#Jo_Edm_q_YZaChgE!_6(o4yBk$^6EG} zFMIpDyLJA>hs2OO&pw`cLPc#J9Dn@52ZuW_*gF_35P2V3;i%-Nd;6O&0g--@;@81P zgOvc#h5z#C-?H!<=5T2thjCiQAMD7~^#MEbh5qVDe{=hu+Fxhsui*5zw70rFk?n7d zv*x<*!;YeEb%<7$qrWlGU)Gh<{<`*@wbocUZGk>#9krDhT1#Uqk?Uz$to_ZZwScv^ zt#qs2+*u^{eueiU#nWL)`{m#%sKuw`@|m)kuA26@ds14%Yx}NSQw*DS)U}FLI8Rrm zJyKJumDF0^{-&<5?yql8T2D>;ZrdnHaiOZZth_6rwOh7gLYfkfx9_1NTkU$-PrPOb z(gN|aos!3Qtkjd*j+tDWF?N@3S=d>c&ON?@qtJZeLXIe*lmPE13m5t^pxL|k?%xczl1_RLSks!P+U+D1DWp&zD&X|CXpLD0Q zTOU22@}F`uQo}}KeM+ylft$j!B7PZbxK93^IEQSD1=;TC(X}SGo^++M z47@3wRCiB0+JLA~~J;I*1Z$E2@`JgmxM*l(pR@XKF zb1}lJYj+6ehQov1!M9&>jP-f)ZtuP7$Wy2=q!&cJ`P{REa2Q)Z zsYB1ux~bAyLifeyj`H@=h+dyYB}yPhTQ zrxh@1yljn^Z`F8tdgJB0HomWb%NoNm9Xi`CPRL@~-QGKd1P`I<(ZViS*R^#T@iU1u z&haIbRvV4Ak9rz8Zo-LH@r$;KpTAZ7e68YQ$}*#Np3r*zjpA=dDt;EJ_zW*iN%hfS z<~82mx;1DMDXW`12ZK$tn%%)aAJTRe`gY?+r~N6};JiH&BQj6T!37H#lVq`gH`B2n z!-BZB9mhHZv^t&(SO>2)S043CEMsbOUKVupv8c#Kvs*7tpf) zX_SSboVd*E1Ebc?Vh?>W_7Kb1LpK8Gw_p!_UiQ%EWexVS#(hSXo*)ebsar2NKp&ob`S~3x^>A1QyE|p@Z1N@ywszY}*1;y4Ms*_X z1_X=PztuHw_GYSIpCFr&rC%Scrrn+4!F-GVzBaNgvL7yRaVBzUsqf5ozc0&7l8#x( zl8%k|k}i#b#`<7BXHQ!NKNp}0v}ALz`j^h_Dcfm#Z*@wqX`QmM-QRD0@MgiQovurC zjMfTzSrSI=!}fhIY>vKl623l|`SJ0`gBbGDwj?r9i@yzbcSs$8nWv>c9l6gl?(EC3 zby!Bou;s}m?dGyN&fnt&{}siNi`lX_y}KKKLxX3MPe6fjS{rFa@OUOe z-QV4&;Y>*V%de|V=+fF~9%!?I#|IyOH253)+u*N%9i+jB`0oFSKT?>`Wv`(s2LCl^NSUp5)yxb(DjQDI z-5Stj%P3XTY4qahoLU33_)%sA~1ZqE+UxDnG7<00HV!C#|Pklj-_i}J2_0cAZb^{^%H<*6~Q ze=(9HDr2##ZU{y-w)V_5cD)6RomIo$yVbCFo*GWf)-*7&bjoTxwyRyc*4E~!ago`t zNm0Z3qDIX9;&jAz64%g^VKcG~{p`IsHA!a@$i|M@W$@AHK~E2E-)=45E8D9x2~U92 zQ^#n^cN9UlbY#{#hMX&RZEaNJ!Wd3T-xU1W4Bv&ty_FW7mABFeZQJCKa3LXaro?SLD56Ycz_jxOz$iL+bF<1Kb@U2RxIK^|6 z-Ua$yfGnfPz_Y3H91ka@LpD!fWVEmW;kAv;F8kpBj-w4J?r?Lb`#vs|EbyqjzkD=P z`r1sK=LGq{?HWFR8bf-q`p0Ho9}oYVNfX~p%oF`bWl!@03?6{F#|3xR>&__Y0yO;W z?t`!He|mfB_COf6!@=#_XkRBJlXBPYoPc^^YkL>6@Ve~pP8Ts|6#)fqt;%lt?!-IL zZWWHv(sv;4>SzWHMUWcYK0F9uM9)nkdM*%S|jfj9^6 zOu68+0s3t`{1JZ6i#szsuq;BgC;pTE+)QO_Yj_DEpr^-wf+kGP$A1c@`G4X+ujTWf z_|N~ufBq-_^Stq&ABL@GyZdO!_Q$8jQg$;Lvrjf*1EG)S^PPOOT|ms^*(d2_>3Ec( zwC5hd9zXwhHc%B{V0Y)%eyM5aVB`7T-pa|BaTCU|?C_y{YJ4<#({Ot!F8kn6}=*D9(njjnwS7#=t=28rslRq48Y;MQH z(yji3E5jBXjDU_q8l=4<(HkjH3JLjE#Vp{t|XLMjdXZEYTqifFW_7En>6u;)Rd2+kBmn=+1kV+i>xPvbGzWOd~WBm@!#ptoxq zK-6XbEMNKG{5I6H1q+fqJtx zf@q@xNWZOeD=55>n`JL=a*J1dX}<9`8sFwyPfhXFS2Ue9`MHo7@(z%@x^i=r;^YT; zR-SGO3Ig@rOz@P}P#CL36Q~XNG_T9k5wLBXyvTUF!?gt(b|dxS&5tLO=|s^-rG7Ze zY#$F2|AXpWsO1d?U;MG8`ZiSaiww_cV*8gd1Kqw2H|u#Hxk#Qk}3>hW8-{s#nQ4faHbh*oA>!h&&ZDl>a*&>PvsbH=bu>yl|6;NJ|CH7;k%0Ban@~;| zi!KE-(0A5BLzHL;Npvm_g0Ffy_MqadTW-A>-f#Z zTW3y;>jlf2v|&Uezic$7@7`uSeBXFnw7k|evAoCP>>lH1+A3jxG)eyG{^yV2%RPAb z&C?(5KYH-l&qxPry5EHK%?R?fdFX>zyH6*`d^iFpvw-EVgE%DowDiSjwX8#A^zwj8 z+kxM8XYnyK(M+dN=2-RN>&7Hor}$PD-jNnNNrFjH(-_oAF|BE{C5=iMKc6dT+^f;F z;=v!N_DvU$u=uKbIy~42dwa-^^7!mnw)y>qrVJ03wq*2p-kQ#oD=x9zyN@5=fAr+( z{qI)ivain(3=Df?fr8V;;W(6Sl5}Hu7&~i0L({FCt`j4SzOT&)PBx#Zb)=dHhr_c{&yIX+Ik0Y_{j?qp9uoV{IA3sUC(~ zqE#1aly6z1?x|5PuW@{K#Bz353+%3^OIS--Ud^(6U(&gdODwX!nY${?Htqfj#s-M zYd1#k#O%B7$J$DdG)$-_7O5uCd$Bf~a+Y%9RLXUE=Q1zDBMp0uRqVX9yy;`nN%p68 zb8Bl#&YktCx4$>@{l#?cacb)0@QEz8L)1 zM}xgnJF+*|kx7a`tDnDvsEx1`owavoK1HMyNOEJq*OsK4VZNuY_BRj8Y5;RU9Ku>x z^j`-PO0~6U8vfzNXrULSBKhpkxIWH=AAe(i8|58|(c^=%H<(fTgHCqBjOfHpa&FHN z`t63{Tmvy^BhU!+f}-H|#(Z#+GOA4%o|`|7|L-GjRw&b(JD0;)vqID0E90DTMt|`S z{;o_?wfVS%@yNh{Z4lqD&5xE^M0v}pG@eZUWTHgY2iswDr++?q5>IqaYEe>}iR{FA zra^c<@m2s5tTNh4t5&)x%O%>ae>^H5O$c-GX1(Qoi$Z**W+H!YPulxw$qSm3TL_>; z8|?as`nPT^0RerbKR(<_PLj2S@9J<5_3v zqyJv%j9L3R{xQp&M;nvkpANTnU#)iXb-XcC>sps^7LXp#{Thw@lSkj*Up*q&dwjxS zXh`FTn4;A*v+J~L>yV$Kk7+4{pDa?0iv*u7D^i>)iOnZl$lj4)whVb%vnY&Po*1s( zSEB70pzWw}$U>S)%brKdMro7(je47`%E;Q5vh;Fu`4WfHePdv@w>;*2iu|YJ1|1 zZQr;tHX?JIKDIkk-pZLX=W|@YtnAGW)x8C(y=WFblO&!iRb?v-E`O#_ohk>5UJQ~do#l8b0Am5n!BLLE^$&Si6oK`TP&fXc! zrQMlLJDesvsViq`NP`L982r!w3`XDSFqZB^!?#V3+Au86$qb>*b{3wUAlG`2W}2+| zO;yS9`r!3q>&EJv4DgAvo8NUz?K?W5yU(Dv0>|M7TzU z;bn^|7?l0}-TlA(_s+_l6Qa~@sdzIe5am(s-xp?X_7{G)>VMzZq43bQ2HP62Mx2CJ zEk2(5wd0k}u(Pv!FqotR5QYMnY2LC1E;Mmc*zaR{{XUYT{qckSr9LpV{di;ejBx13 z12*e)&sMrWPBPt@axw{RhXMY@!}N6 zDF1}4-A;m|{^_6Y@CsVw=;eAE!2ufGqS*Hjr-2;vY<;GwCXF0J?o4jm!p$aL=UDOc z(G;tc%U#a4sNdG~rTlfqGu$rQ03oaNrk$~pDC*>O*{$u-+APl=ZH)Tdg&}lVHrHDZ zXZUnx<|AYzfLA)5Q0ls|IsOUC9c=C#mN_1!%5L01KR+DkX|bcoY#NoW$Qd>nk+f@G z=bTc~nJLOP3gcNyDyL_X=gkMbC2sbWH<7z;cjopUNKEcR+y68-Ax48W6D++rp^YKg z0}C9~RTP5URLXBu;eRo4gqqv%{r2k#&K|j_$g`|V3)W&8-yd&mZugJuoq3vcNv8|; z$7k~IVs+po$m!F=9f<0jfQ=Y!_r-!He#e1*Gvf+VFyC2j@L6G1Cw;Dw30`p5R@jWg zJM)+?e|)p&ITx}g14SD36vegmf;lgwmE3T;tb>Bbz0-_2thIZwJoSwesl|yliP_9;dg9da z=z=d7a*WK-%4N!W_o=6RR-PV>n=+5q+WG+C@lE=6^XBH*;7uDmXJlsm^F{P|PW?4Q zl}S?wN^)WE;LC^f&Ewk?kjzX^y;y6U4Xk#&dUK5C78?SdZz#9-?R3I}3ZE4Co|d;$ zo&glBzMqY|%>21468uWv?jH)kbRj>tIYjNFu?U>mvMj!cO? zJFE-dz|GMtb>|)3Xy0#k0U@^s6VGU>){Z6xoU8aHrJu9#6B5$77$3~;Qa_+8h0dh@ z+#syaqyIl{@;6J)q9)9)G?1yMdrwMbXZ#+Qy>ip_YjEDBdNUXNagr6x94ibuu|8O9 z^Ic<>Sd1+iQ5#7Ha}*!kKJOgG41H%O1ZOx=2#T>;uvUw`Q&~os-X|K5Ibc6;PAHox|<2znPx41&85>b181$ezm)g zA^Z6D?QIGmcyrc}PxSI7Rdv=%cbl1cRO*9wpP6Y|z0IulFxAS_eWLPs7N@JV&5Qj( zFk^i{b1HAv2e1EV_-J}E(@R{@_e_>%J*N(^ZnOZ`7TVC^DBnYs8W}NVZXU1wef8+Z@np_(wT%l!W{q<9b>a2Ii$9TqUL7r)m08&- zuLdVqy+$jmGgkQM)M{6Ew=yl+kII?y?Caia-DsT1a6~~z)1OOv`}!1-yXa>|L~q@C zJ&Ht{2x=44?r_G}8;3iazaNg{yw+}hJZES+(k{!sK449-r)wu4OxECEqm;$vtu{cf zM+~wts%>fq;mChH;PZac=7^te+}Ip*)6pd70^FUGk`eJwALVmt)U==IEdSFL>Rdn! zRet~L#}A%S_~Gcq z_+c*T?K(=^!s!N?bM$of@Wj!P0fVqli=Kb1P+5b=PaZw^=JUZf-+%qd{YQg`-`uBl zh9z%4d-(mMo>x!4cy#~%$~3@rp2WAQzAlGDs!(%|%Irx^ z-N`_!FG#T5c!`LLGoBd_t^0!J4VP7Z78TD)!CO9=4zJ#`CQuyDhYL2aQuO4m$93 zn8MD|!x+XmwI!p_=GmXI>q~d`8#)>W{~E*ztcxvHEp4RT!<~btTP0+QwV`9U%4|$5 zl2Nc>7^T||2kANK=D60GshN`?!rV5!6*|FZw1aQqMJt3(y6N6-jspBJDB}m+c7#FQ z+#eqFge0}9Nhz28{j08huo?zGJ$%$+)4RQy^JOksdF>8#Bqm#TWM{xy*l2~eWb2deUonxoMxBpJ;%!gWi(kO}y8(lsI&ou+$xFforLt}p_BZFd{dp@6G%MNA9?@~|^(M604} z2`zRsJvXz|5k{(VW>Ejwrw9x|1-)4^YdQ+ypmOFWP2*`L{q|-&;kHDx?ZPk+-DajM zyW&FkU~YfO{x6ocK8(UkVjJr2pMN#G(LFz_mSvP_6NodUS(FGW;6w-CP-EuTC@zw3 zV(DhQuGv<1dlDXYp!6)u(Il~}y&UcJNbodd>znfI{?Xnin>$bFgu=fL4nkZXbn&I* zfai9yR{L{A4#n2iKAn)ZNq_#tzz3SC5a^2RDz7)?1zl z5S$z&G>Y#Vok&8_->WlzAh~nXN0S)<@vqgJRNON7HaZQdjm?P>Zrq zyjZ;{bho@aPRT|UcT?<*#w`+Um11&_$s1<0AjHef5e8U@JGddnmTZn(5 zaSMT-t7&(CAK-p;aQWtNu=2soTp%T6quM$L9*zIMgOz3lM~94#N?2Kra7R?6TTZ6R zkxuwJk6N7PF=8=zsO`1}u)_FI%_&XC0z6@y&EeB_1nTNyi0X)0Hg`4;HoIuhlhrL$ zwG`n~ty2b>jlu-Ln8S%w#!{$AHx^98wN~fXg{FIh(Hp#ey7x-7qf$24mX7MlWH&$V z0}UUq71B9!+bJMz|?9q+h#pdLnjKg2~$XDfOIPhB-Tl zJu?a0(C0`a&Q2sZxZ>IiqvhF&p&$H2(-VK6i1q8FYOL``QO$EKxg=qCw(B_Y#f$_v zyWdWX0hdt}=QrIbJNM?8fC`&NvyUH-pupkw;TEa>p%k>7{i5}MYEyFAI%pe0Cy&-T zg_;&s?J?oOBf^H0-4HEvi;3o^Yu!$-{=LaVlYkfP!7Zb;G;618)9zLC;a1is?QKuH zADvt+DBSa?(2i11&!I+7YR6e78;v3HSqlhcTr$JBb`t8!tPd2U%SDBEjCt<>5S23$ ze?~`^EH8<&d&a=mEmTn(x^A{Bi7UKN-YYGIlH3W!PAkbXuarj~D~w^vI=V!3bd;U( zc ze16vWoy;-0^JJ-|nJS-iSewPf7qvM5?jx-K^LdBQY3IKWx5NGc?PGbzGvL|j=f4|! z;{11Ld-I?3->>8IpYz}UbN>5(&VN7e`R{ZxdEQLD$D&V;Q=fS|y7pt?9P>z>xYhnH zys4Y@;MQmOGha!2Ofg8qCC}T*<_qNvx6{qC^RjG#({45DZl=4bt@6y5FqiP_!>xl& zxPm{1t*vre!pCGB?!h?hhedkyr@ObC%PDE;9Ffn#Ci`ckIkR!+Oz?y3J6*n8v3#53 z?QZwHJnhi>#}JJ2`C-`4eF@sy?&!eto-|K3w|n1x8xEfTuvuR9ye92GY<%C7 zfP%Vj?V*r)qJ2oy+2vsFVuSgg2ZwuG4D4^3&tEp3ZJ zaF(~I*43v^KLap*`gGx{C)&$2DXD{{%?qEcZEH8=r$Z?5ROW&fDBSKu?WmB>kDxn! zP}qD!Zwyv8Hg4hnBd|oVU#*aZJEBnkC^+ZC@#)GRw@b`gaN?`Red7k5JV}q1$p;?| z94o4c^T6Sh8}bWQ_8 z4IX^+WN`nx@9%zveE<0R+uI-hLHSmO<@cT46>84S?E+hpQT?Zn9)3GW3U=V}7x$h# z8r*yG@G-6IeEZd>-!}(2?HqjY=Hm|@d~=T;Kl$R(!yg}f)=i>9@569|dxl+0%F(DL zaCloAzWVg>R}b#p|EYChQt0?X??D>2(wEdu>1efq{=NUrr;iu&(0_j;!~f!gA*WMu ze!BPV_cL=fi^(Zvmxn6sNF(LAHy~}7Wp&UC_OYEVx9y`JCDFEywN;cHyRM(l{>}oB07y#m z5~sb#YGa8YFc=I5gTY`h_|Q1{aPnyudYdq>0~C&xRxC%_oM6};Qd z{8Fij{gV%SyQkmEgyY7Ku=?9M{$WQ}BQH>ZX}L#Q3SQsz9%jveE^woHz2)`1K^tf9 z6{>T88!C&p2&3&FtK;==?EnWsnLF{rdvOB&4OM?Ud2bc~GOR-f$*YE;qaZDhoQeEF z?0K;BBk}0TDKig#!^yMre7HvDVy7^B^vCMYFP z5%GW^W<5CkQS9&h6WLKiXBHqXEZdqYLFPjdbRk7YK1Ww|BJ`kw(Y#Q|B*W1zLbm}$ zRp`kGG(imA7dqiqM)YXxu#B>Rq%;dbk;IZ9syqTwXod2~kT?W(HkqW<5&D3pVp_FE zaqhbxKfwIX;z+VQ$*4IcMYCFF7T!L5d%Hk2UryKwQ{FAycxXb6Bq76yMBf6f;gL&| zBMjeI0nGUw=9nWDA1)GSO2n(mi%?7uis~zQoCnjEBwx2<$VXe)p^!wqM-KZ%Wj&`czt#g((8<*>VkrK z4s0ZXVy3(EWylpZ9hlQF3$ zif%^lA*hioCnYFJpxb4VCH$8V^t`WqN*e|R5!qo_vYS`ZqL{aQ!zZ0)YuJXSkJ+Cm zm$n>ExXPJbJJSm2Hy!cS1%tJ<2tU4{4jqY_go%+qa)d@QG>6m4Xo{Y#Oq9OgZ;q#f zCO+kKBSJRZ8z~L^&r6I@5wd0T1#z48S{@#uC};0%GOF63lxhZDRj<`vo(A))T=0KJ~{p_pf1z$`zr@7OlwZbjA;82^LGPLi(H}+*&V2 z@DssC0rV~`OP8}pLn{}*=bLY8N5;Xc7ExJAXD!N+leJi- z)nav4d6_4tu!}$-fqV*EN~KLxE<=!6a^-@CE_0jonC1*bZ0#~I8ZGMZM9%8Vyo%#r z<_qJ(4l%VofSZPzbaVmrC~TfYM8~sW5Q(d?F1TLe4@oVonT8_XMJF2qAoE2EFxMQb zVA6PQfQWccSeT}SRmYFSl|7_lX2_K4xdR>s)s}3~PD^+}1?dBhPUXoFS3)Nwl28Sa zBFS_qmM{8)0B<3W_^`v#(`nBFSZ2~`a9^&iQ8cMscIRyM^k4O}kNV#c3ybIL)B+H_Qi1d4j^K*n~iK_)hwQNE-xNk9@ zy)Ekc-X+x9)T;=k9r|TeP|QRpZF@aMq5`pA{vm@|uk4FUh^Lnhi%SN*p_YhP%xc*@ zYnvM}akX%!*jPf{N@+mZtU56NawtF7%;Q#pJ;bDMY31Ur}F{G4~sbmS_7i;Xa6`cbe;I#k(nl~PI zJ5lU(IX{)7!-RM1Gn<96GloHP0`*D#5j7Exu< z>;DpE^&X09y_}+~Ub!#o>Z8@w1Qqdz$`dGw+HTY$dZLznhN}2Oa^?La%;8Tsjt+Xn!oI=IvuxO z^E&0Tinr>mx~{+K`K#^KveT)ac`KE(TBp)3cghLl*z5r{b+&->+CB!lc=RSUZkwOe z$qH5<7uv1R$G*a89Q96KDWCOXy^hxk8-p%wVMIqAMC1J6i|A!iY2(7p^q z?v93|CJ6doj|RCn02vYq5EBcN9+FzxnlfCNX&z@Lwi1dA0yetjn8l3YD8k9Ob1#Bb zoQAi*Yl(rJO!N?IGpG_n8>HbaEWa0_6KXNJSu`1qeLPOq4E#YS6v^>y{ouTy`gMiR zu)GtMg*!H>7HmbhvKaekczX&02EssX4{4n>R3hxr;WKO;CY!HY!_JK!MlQi7@(MaT zueUSuA$^B@fR8zZqt6SP6(Ftwg-ug<$a9W#q;CkcVqOaCF@Sla5mFM{AE~Ie+KT8v zULdR%p!zNY%**=WiBy&fQi^Np;fNb9Z8`=`&gs}PywmceS$8xy&UZS@*~TGk>99Sa z2~6DsA1XslP-y{}F25ozh368}HiW_n1Hog#rH!}<&<4I%O-dEH5M+W9_Zh$g|7y2v zvj&?6jK%gWh-Yz-u_~pAT@P==v7!LGWh1m3p@cr&@2IdoFyJ{+8pIhiVks1CQNK#Y z{u~Zcf};)#gaDy>ne%MXtT+=!m(jYQ7e-CjRJ+eS{G{STYObxjoz2O^%3O3U1x$0| zmJUe_r|k<4HZ~mL5Ezc%s_TMr&NL5_!?PD$zQXvNbMwfs#vEZBuZuQ1(3A6p(Tx}c zhl0X>BO~Y9rXG6vmfmSbpNt(s62t+u&1i2-J}9&`3DFPaNK9;(94*Y1$dCgJ&0i+_ zlZqp|y1Je*L%FBO-VFh)MUlvp_j*F#Vhs7r$Y zknHCWkAnE+HyH|-)QVe0`$P$tBKgE!UWJ*Hbe}_W+c>QSv7?m@9vQ*=0V@bH5zs#| zn;h)o_f}37DQ)>7m{RO;UFqza$3Ccb?< zh4-8U*{as*zqg92M+(H2D!#R{zzhQ7syQg~YLv^N?B6@sJ!GrZ*5US!ywVF`5w=O$ z-ZxIPT<5@H)4=a2K99HRjd1X?ZnI_37}9X8ri3FU-stM8%vxRjP2VNy%a!w>dCBrP zvM!Ij?l?CiV0f9>^AF)HK#WF>c;Um%<$??sc3wRuyxst|~^t4*#ls9Z`JAnMLwDYj&JO z)8om6EL237XwuW?yxMx^FFxl*b5bBR|1UGCX%pIFibQNqZsMIt%6^?TJ4dFGs2N%l zXSRk-V6ho^F|FXKs$>~rw%S%{qqoTiz3!(o*pgbqovYIlA{8UtepELEM2Ww%#({}^ z=NoFhLP~y)rSsNtS2kE398cR5L6S?ez_9+(?X2rI8Qna=vVmU{cn^=l;wS*WZo~Y ze$zB|q{N0^hpo2jVv}h=fYu{9S|noT*woQ%19!g-3AB*|`jecixOwp>68_B_y==7O zH{0kyL4lyXYQ%o$eOD0Q{Q-ZVwM80IY_-qF>?Vwu%(6cMj8=So9h>&iMwBv?Qh-SL&652W+w_mmU0C_u{#L-vA&0JoeyVf8_C}R$rzUs z6Bo6yRU8Zl+WpY@!8x%zP}f!{ZiYc*Rv)$R_ae5;0E>?cwarj8qA7e5+E@emOJ-!z zMz<_YY&Ilgh&FI@Gy-4o*eS4BLF7zzKXvNTwXd8Sy9IM3N~}=w&@!gUVfhm@Fgf$n z%`!yz1fu}=552|hPYRPC^$WfWE5TaymqM$*yB;PR(R1f0dwO5rX}uz+w@CYwHOcbw z>9<&Kpz^0%S+PgrlAk4t-XjlOSZV$M=}KZ`UXdCmtwb%%yFnATVw1Q?o9+`dOyG|^ zcg?yE4|KRxwlrFf!Xp&Wpu`UH+JvZPLXEE`%vTfOt84hu8HriUpX6|Q%ZvXL!jgg_ zW&@7~Pfm^(8Y%|StfgL9T+6F9nRjW9${NUG+Z_O zW?&NLi6i4OHf}mPGb9l$JrX5RB#R8|BzH-~HaH6U{`lNi8j-%it@0V0jS=E`P4EcO zf-!d)mqZaB?&A@0lQCHc5%pavJ$?JJdE(D^Iy*@A$4)yRPMYn(M3V(Fg>H1Rm{h(h z7kLawZ?gE$r#@=?pGTtS+>+FTe`2ha#mVgjld9zeJwMYr-Ndso7*~ zGAaJh6(*vwEUe91v9f$sB3`8XPSG!aso654)i7&ol0#^RC7jvTlbfsRE%2hoFG^su zv?}scK-cua#8m9;w*2`g<5pD67;D;mwA3$s@nVo&WiW|P6V%uX{BXLGt^neVnvD$Q zl@~!dH4EyC&Xb8h!titOH+Op*&Wi=%-W9}cxZH#lnRIlK_aA>_O_WFuT!OxRm$U{Y z_(lASlfJ~QR5EoV>|wI21lo?WZDiZU6(L7E!)#KQA^{TL%(RQqeyvr^sPU2aFQml( zr>N3T6k?v@{?}@0@&7qqz7hZ5sn_e}{}8pOLSWYC-#q^Rtot82tw&z`AU`wje{hy- zj%)QlUZzrgx&PrgJ}>t_yxjlra{t49?tf?v+h%}#NDDpBlHVj=7txpu``tFIP?O7) zKKkR!o_{nR4rk~1H0q#AXJ_fONeyx@Ya*-XlCIvi}b zl3tvUDSp#CKRiPq0q45+9Sbdg(7xz<8QTWNC#EOTx+jrkyI;MB#99;h_(Dbf^UA zwW*|rd7ea%I*m91==Qiv)A^i39odr)4X7m>dSzSij)Gjfw{Da`c5CM8{TK{h7LS46<|3Y>xN?=beHGp3wVUO9^NA} zsJ%#MNupw0_(^0+`+M}#{_yiN^-&LM>VbmVdw4%Fq~_M?Poh1!Uc7^3xxGPml6wUu zLu$$wtS`~4g1Bd2Nf2b3!JaAzqlTyMuhS0t0zFTUoo<6N{qWwB)6eO4^Yp{(NwK4VFJUvaHdOONINa-~Dn0v0kCUNcmJnI!a>v-v}A=Eq*{W9)2pOT;RrmP36BW6Q&h}?~UBo62rg$olXcOjD9Mp2E|-L-F+QmWg@1~4iQJxqEm%oy3`ia zc|kvjtd%mFArZjrq@WImlkf=Kow170y2(PW*~bkPbi4UdSf=1HV})Wih_{*y!Ducc z;_dH7oM3el&oGF>&h@A_9Q$K?8XP%(?(#d=6a5L1bZrgI z6&vEJ8+0eiJ0*qoG7papiB+_M($VsnN}9w&Di@LvRh?rH*Uw>o-G!XS-f#rNS}OyD zF2dw69OZ^1V;4+zpHCg^M~LZXSmR5!#HPsgTUv|sMck}L5U)<6dB4k-@L8@ljy!oB z?!9#A;Olt0QZ*OJC*VvpyL`D|KXpW}<^8!O(i- z&UTx%Cjg2epb}}Mzza@I;F%~rg^i;OeQ%^?D2Oz6ZmPXfjU2&o`7)-)dheHv^U^Pv77h*j(c zy28MpXhM7^%xMn_5Tbf+)uqD`H$r=5QmaU#r_GRb-^v2P(8^)+NxE9;$Xd`?P5haT z5m*jWWtDdE2qEPUYGYz#E|tXI1h*81mjYddu`F5A1F!Gne#FGT7HUot7_TbON&|6$ zd?tI|aoTgSoSek+w8)uO;@_w}^;7DqR1r6d6DWsEKXpO7nV-zZtY_PiQ&pGI)V8do3 zo;E@)2s29AoW?Ti_Hcy$eHydLwOGM~eHT`$Vt$NGqbyRwmP(OnE~<-^AcHbxCQU(< z=T>4KGnPHBPtUQ5Eb!=iQhF+Dsl0uM{bwKhVJ@<*8$t|l-zQYdOJ3jv`ki!QC+^aU zDHflR5rt<};&LKEV(V@FKN<;Y*&Rx2spCeC&~#i--FCazv@Ai@t>ue9{PB>j4p}97+ZwDY6JI;_2XP^U>F8%>__T{3z4A}`P4Y2-N~@|7LBBxhZm0A zFxnMmIg${H&Hz4pl~0n+=HvOJS^AfUDrC5VFB?mCJr6Ik)nc;U3bjbw9KdLZmI(l; z#*0;StVPL~*Gm|@rRk)hG3;MFa{q-}0tz~AznlFI87$}Y0gWsTkAKlA5iDzvRcwd~ zXacm+Y`$267i&UoLfh|j1=eZ=%f9QJo*a%TZ<3n~%`v5`!Yz5)6qgl}|0YA`s4&}| zMnA;IqIR@@l|)1qe-^dEYWa}stE|_`8hj62UC^2wVt}?3qiQ5_H5oKcYbH$8z<#|x zJ0s=m*Xvp>TQHUn%lTN1=6(Y-3*g(wY&8o3OG=TXYG_SJ7WLLq2OafVK4d1X77hXt zF*~K2%SnlJl2pd}!|H8we!;3I;b5UWkYUMc_!plxVo2HxJ*S+v&Q#4o-k4I7wjz>- ziaLRT;V5ax{Y;P;y8~f`-Tlu zn#2!=;STEo-6VldJpP$C?aA{>l$yBzrq?Oes#vF(sO8Kuy8YFxA+q%9C1`H44V#GH zhNMz-c2QT|?8Ss;P*2buUrFSaHmH8ak&l&5nrA)loCpM2LPH+HGYxsF*J+_Ii>alq z9Vbk^renAmQVnzI)4H~ICg-haPoy2>!nnJZ*+1EKRZO>BaTS4@R>r7=>tuwLyJ?Mz z>BFkYSdF=)d8dZZ38$Yz^4gl_Z)%{S#uG!NN`A44{F`{EG@Y2{vrcQ51OK zK%Bo@*~RqiOzy&|jdt8%J>3vjg_!{-BK44Uf3l`W3jl{{eU)^ejU&7anb47rr-9fA z5B%mR-jAVc2A{oA?&_B=%#v5X02md!=PskK5C(>Jrl#-tZCXHsn-#@-)`E?Uk}@t& zX#BEmUvoMpg2_hsJk8>gJPZ&R0BOz-Qiu9Ke1O;9pG;h!62z1>nQf>J^7&%48k@2I zYjsFKJwoe_g1ATL%%Hsancs>3wq2#K`D70;UMi;47R_!kxilyI%&p^A_&Se-gZ-!k z7-#$E_Ro4GDx@xCk7;Y;vz(tr4ee;X(CocZ#Zudt9B)S3uH}iI$rAyXV(5nE1dq7r zaZ-W{Z|rxd&p%;~Q^>HPAL^F{WqT+OPY5z31=kiqU)mt&f{_+K#cqHbYk@*Ns;i(E zDB}J%!!k~rhVOgBbEANZDMs_Vfg-OA1(9Z{4EK{Y@X`=1&+^7L-8hnkxYJroiZ0Zo zF=P}`OwueuDYE()y7N_cJel&!h2TXitWqhWgEK8~b%yS%lRkpeX(l3;UXk5(mDH|_ zRr0tVti*bdfVy*N8u1~@4J&pHL(mPy9F!{}o=lxdych~L_1tvwRTn3p`#AblCH;)B z)iEKtHSD*#1OI=otaR=pEEkhi^Q3JgQm7y0mSkv3eyA*dGHERCCwm=@^@MEF{Rg4m zgnNr4M>j3aoedWgNM^GZ8&gg=rouf0tFzs|d1t%v&VGQzeN<<=U!b$y2XwYOx3itU zdvBX#;IWM2JU6E}Gg+nSJ&9z9fo**`9&CCuMNV3&)&qDK?;{)zO#ang*rac>o)C&- z9;pdq3z4?) zkuE;p$kmWzu5Y6~lhA-2TCXLiq~9Djv)}`ZIrGYyp_k&zW6dikMunnuxOoIPX90M- zjnl?Hm;6WQ=%xF4;<62wSw8`jxaIYQEX7ftv+=P1IOF7kUIF(tPcdR@#U-sRc8l&~ zC`_=_NS8sf4~Bt2<%ZOh&ve=wV~?@1YlOJJe0&nw7>4{?U@iSqz94joIcHJL_z}@U zNyq16W0F%LkYb04#WLj}##$)?tC!C6ju37Ca0tb;UTo;hzo|boHubZ0jZJ&6R;Js@ zW=s3tP175VdN(l#!4 zuVG%B*9kxUoqNDSWy{8GbIZbQ3(9USfZOH+af5PHg~BZb|E+>00n`!;2?wP$=F*P( zYuf`~`l!EM-@?cJ7rXHx>=TI{-TVRB3gSEQU9$hBekUtCVCp;ZcrIUV!6&%+&Iul% z(>3x~w7lN1e!BB6#{&i^_)0kLa$d_Hx|-=n{X=z5-7UV|D#ZFT5)#@ed+ohEYM;yu z?%$jn7VfCUCX@Tn-JM5xcP8a4|1Ok&$WDzJ?;>)#M9szUxr{B8)G9TKkT5&0l(zp8 zUV@;`*rT8@f(*o+@Kgi?k_CLvMOfSlW}w%hoqQqRGOL>Clz)7s9@3$pLrJ8DRVk{= z3pGxIYqv4NBZ5@0Am3*YRpt$%ii#9sKpD2bfNFGqM%B0eX7Q(%?Y>O;7?xawAs@ny z_hCk(p2u_G!u%KKykYyJJhFU@en5|BAUBPFf;a;O76;``fAknj>F!#*pywm|A;Eq9 zKxX_b64jX;Uta^EpFPF`zjS{~I23;OAnsj+d8yJzvuqIO*(l=5BFr1coiVsryTxc8 zrA;Uny%Q@Whfck+xuk!{*a;ppc#P4reKYX--S)i&udcrgdmK@Snwa|1V5rdeae0+w z6(c7^BS@%j8tVXEpp-&g3l?kMaftcQ3wy!`Qpeh5S<^xH_o+`KaG&07NSorsy@8&K4+AS z-$ox30LsW~GOmJ>pkgHRM8O1TuGt+tJiE9g2Xj@&k8uKW=fpaQ%9*=^kfQeB7>)fAh=wMHzmCH5>8o{& zM~#bhl*P12ALm}fP+2!>kj1r3hEi+X6+A6~biyL&;+f6z1+2PpH6}vc=(^e;c8)g> zPxelKZXPr~?qHZLG%8uC+dG?|-s2r6PI$}bBC?lHDo(r}yFW`Y72b_YrzYhKw;al2 zsdVTUDvEGm_(3i#mbZ)O=V8g;+RTb|!b*4|`=;rIr$M8u_^2YfZL@3?vC{vNQ-Z2P z1&l{-b8PcI?jOC zGs_13fIE}KzO2^riQbye2^x*UcYBDvb*| ze$Suy@sVtzx=p$CffOGv@6yIge27MBS2%tQSYe0iiRzT*OwNwf6Y~x=C9P2T#yixs zW*5XNrf?6)E7quMV%Mw17P_nw+x7#4c(>I_f;Lh)Nhgq6+HZ zc4WI4pKfG0t|DF$BJkb~GG}P!4ar|ANBN@Iz?y3b(}+Rx#kk&hWyb#lafaM<*j$NU0@n4)l8%ndY0APLF?X9`Brd z+CR@dv44;GgpNw2GM|>ujR^rmD%$Il^Ue*%G(wN6wB~oW>2^D>62GHQRHD zu))=OVU2&x>QWD*g>&0qOA6v)RYUeYTr8FIv92H=A0p<4B5Fu>_9M~#RM!j=E3(US zX4sZUo4e0xW}`XDhdCc~8Y%2stznEdv`OM`HmCTnVOI|XK6BL18`Eb~6)t9GkiQ5y z+HP7)zu`%rpiWL3r=L#9^qE-u+hn`xrWg3V?!ezL^aM$;N5DmUYy!-?*)&{?gr-bn zA}FBuCH$?mfqb{91ScnwWCit0?#(Z@w;GG47wy56%M@cpxBcIr;Y4!F-^R#faDd^{ z8#+kDTpM%5-{_$$1Hp+aO) ze$=GkTgk*UfVw-rZa-HQShpxFSOJMyj9P;~roaUC>V^m)Aq{_gWx<9dBYvh;g+aSl zuZDOHuoY;{%z~SK9?0f*^NY%{!tuc50jz`|pJdd@r|c6bq-k{GEpw9SqhY|RHIqeL z;TB4a>X4s)7nmLeF2;EkWDUr<0Y7h|d7camZTq9iI8r?lgSw@+ys7ZexG6a|WeBT@ zDu{<3RC{9taYJ1CH)dR7`+|*_qYiIe`8Oa(^ui*62=KljUNMA(J??vlrI9Ww3q_)l zMH0_Cf-L>4P_+WlSm6fEk;}J?M19fJufxHt%3!o1M_sem4fs;DBv#a11VhK`(Cr$p za?Vlqf~c#grLs}6u%35w&={D}5PSaF#E?pOz4Jm?VF*2K0S<7Ko|%$`K|cORHLxgsUV&LE*%2aH`c`FVvhw(H(0GC8)*sVr}}R z{M&-flE9}e+-faL>{VsZo_y3$BWpZgB-~_^Etwf{nK!tR%R!?*b)lUofnG}iqS3}o zkynETxEW11!>F24z0qik$qq%SN-0}kK(H|EAqNK5d^%?ESy1F)lQe$AfvY*e;h@23 zS!KlWqJfU;Bl_C#k)%9)BhDn!SyC4NBB-TzVMfh_$@jS@BcV@en5`geR=4ZBOO=Ab zeHmbusQf}5Hd8Q^O6KWj=BoHT2G%>irC@!bPM_N$v$#US4br&6Xpy;lpU52|#3Y#0 z{|gCG#);S(Z5odJi&WT< zl+t`NtTxxr$or3f{KKron)hQ>Ngl+H9vD6Q(@#HT@rI@NdkcfP0mHq#9&w+;VjEyB z4CmO+J$AL4ecB-Pb+n%mw`qAG-|nPO7P?!aRbHSy_Omzc;HK>erQUym?me7 zYNlm#w{uOG_{5W&?Qy%}wyBiWNcFmT9d9l$UAWv{Tl*2}-5YfLYw>3+ed~Cu;%-s< zZ6S&chNVQ`o2;$*LE9Voom^7&k%`;BTsF)k-YI*9T1@7&&dmPm)~df&%9UT;>T>Sa za@mppT=`vo4S%Yye|7oI5hc4$`Gb64{k7~?e|49gUn>p(sl)FYd@nD<@7k}GTDfxo zDdpQj)~L0z3>CNlz;W01ARFM|x_?5>8XyAYDrKm#`sUTI6?k$TtfdZUmVYfn4Q2es z+AHp_ZUw&USYtJ7F~4*uN$$PHd+wnfG_P~!bj$_NXxaa@0&V+S^-5wdWYV@A%`Qln z5=gMTy<7B9KsYS&`hhc^EVPBNHfey!K(7SU=0F-_p!Bgnz#HOPe%qUZw(!{(ouL>E zVGcxzDo{@flwhQyGiM7H!<2Exq%mWL;J8J606kt^inzy&1*+5xRHN>Ou;a%@;Nv^< zdU!88AFV9VRv$~Uiq0?M7)4HxKkcN|=g3G!DadGEyaPVzG_!k#6PS6DdWa63C-(-2 zeM$t2vo%&LBg)G2;!z4K#(F(^L+tuYccchPa{tVT1#HD=v$`SzoX~r+E6h^d2Ua=R zg)_FVWYnj~G_Gi>o9R+G+_2;^pg4*2OmQmAz)UY_A*k&}$hcfh$yl-)E#%iNUXP;g zcr;Pd%O?51nEe>f9o8bReU!!Yh2gDQ80w|}4=Hz$ zBF%I%3~2MyynZT97Mn0(4M_yCNn&MAA%)5EZfFb%OQ%4Gyyi_P<@}s_%%;T3JG0BH zQ$}&k^1$o+9p2_U@y`4$wC1Cr4x;cdL&n;ig2bG| z;Yw0GkswFnk~T7sBuPeSbiDQ`#O3 zpmAF*h+09^L4?-tV$&_6Vax%v`C=)b51s-MdTg(4;fXM@v}4zsQb$VVjvTW_C!!A@ zc4X95h4fh{>TBMzvNo(t#L(DtnJ=gs<^v2}I1@EhZ8~D}LM!T_8Wps(Ahl^R3uPG&3Ajk;!lbN(?R84%LZb#-WSVRB zkR-SpVZOSa(~f9_*sW>$`7^2Pfs(WULEg9Br{;FKB*~#C-wb}a2 zuPNdbXLdMC&ZM_BiKHoPGOyTudcuU2&>tDC#2gil z9R84rBBEqUEMA(epugc2`Vi9IHM4>@DdN`36c~9L02>FKD`dI z2@fhQB)HvG8M{?WQEc<(tz@*a5sT~XjKXpG_;Y*!e5B$8cu{e71@R2`>JJTqcAM_IHp zqo_5N3I}XOB=N6D;%Mxjb*~F}JWD ztWM~VC^XChSTS>2NR24*VXZ_ax7&zm4~2$uJO&ODXHiUgoGXGvV@mu(Wbr8r;+}pC zr<1HCC1qfG>OdrnC~yS5l8=;KoiS@Ao|d(a%9>NA{_AIf!v7VarC`&R9S=M2(BqAVfqdJJvuan2d+= zcq{405~;kc9%@+2{-R^Wutw;ut-(YwNQ99T;a9nXTn{KJ;?hRTKkp8j6Bvg95RlXp zD{s(8lP#1`nFC82dfOZN{ zc*6nU($sb3n-8RX6uGTaD07!b<{p{WUfmpGYDdbwdGdkID2YE4-=7Xg_+I>}!L&b# z0yeoa_JU7(x8=1j{LStp0FhMAYd2avWE|o2E&kMTeh7q60mxh9a60I92bVc>_-FG) zzAQ@TYs~$5+@1JM)Eev(R)FiKc4|95j_)+VrH*Ht_SVO(9*#~Y|$Mkq>Kjcmphdm2vnQSLQ-NMV3i zu|Vaqv6MUo-E$#e)jTUwx-}Bpz2U&mVJZpucS(v zXmd)49)=do)5Gnef?f2+LEr-)31z>;)5~GWSiIJjw0&6@UjUwmrg2uQ| zjRGkr1;|k_wUBWWU0+U#UWRiK9o-`(x*)Sr^vKC?+Q<*997ErAqUe(R0CR*WiSNS% zy<+@OsQ(bMWoD;t=WTv%-dNY(>qj4nM8(e@#x}N_EMAM83x5<^Z-k?16pE_0>Tj%F zI0&6l`#h#W0^ZpL)5#lX9y?d?Vb~jU4twp&J~u=H1Wquy8TM!VrBJV>$``MqFaBCvD*v z%dHt9?pL*DjL3+#zNvYxJ>>odX&{1bmyR9R*ShaEDjXWCv7uZ|-CL9~YorH4bXPldLPuWG*Bs?Xg& zEy&0(I~DWrSK|GEY5PI>MT~5u18_UyVYLlI8QI*?^PG{G2KY*H#w>}vF3BAgwSDPt zDNrHN@J_qcAk3q!nISVd7Zm7r=DWN->FTlRZcXV~5QbPZ9&um66w48`XaS~yR2v?; zUTZ#u8tk1d@8^y%Q|KvG35a}|_(mhoJB?O}dF7RL_?7rxTWy+qHqj@}eR@OQTG9NN zccgtZMUIA|Fd93$Y3Csorqej|J;DH^4;mX`phkO)JYZl%Y!=NMJRqucct`P0sg#y8 zInVqdqvuuwX1)qCi?V89N$~TvgG5~D_7K`WN7VLD!K*U z971MO=Hxh^34%#$W-biOp7=_oyM*s}yw3FM^boAc zI2y>!iZ`5PukGv{abUKgRH9++Uw0?+cuBehSg7{Y`Tg(K>IG|6&VTb8ZHDuGaI>TM zzS)-i`D~3(u6uD37)IN_5(T7F?%YX?7a$2zYXMWWR?@g^KuZsW^BjRUmo8}g?XR}UW!JEvmSc*PlnBox%XjR;cI#U$1m2RMdR3K>llGjgPW zX4-vOOwn=yuY$$4@Q8}a_qy5lF@%S;m8!Yto4aFXqzt_W5<;Xh$)aAh_9mr_(ubp> zlVXCH3#mLUU?OE683+gSu$g>rf@3h6$M&Ty5MLEEQ4=QS*He#U04S}hoRUbn!brlHT3(eOx*f*+M0aJ8Yl6ZrkZ9>)Qa@gxUL@8oph<>1h z)yPc@d8Q=Hv|~|tb)_CLK=zeo z`YuOjBc+)L#p8NrQN1o6yjItOEFVH`obXJ+RG2YaBsgEFGK)@%dQ2>uYi3P9+3bvp z7n-;s-Ksg}ni%t}R0orc{Xo!d9k-e+oYFH&J5^%9pCrf2QVF*auXU|Q0n$!bT}RMO zM2vTG+#(5Px!0LvUS?08zKbAqF8u4rFUk(ynWdXdGsy=Z927)dQxJ7oDFi9B8cCs8 zNKnaQIPpXiKBwC1()|Z=B;x)SBLNoP+(ni;_T=Lv>Yh2%L>Bv)JlDE9HD`>oLY&QX zWdSevSU}A%hHR3O;hMvlZUmX3V#MCh9Xd9n%9(%zu}7oiN#*Q<9&=ACX1UTux#!{C ze?MWFyrEB%Y*&W%;@`#|t7XJFnRxBX!z+J$)*F77yQSkB-J!|YOqM6;Rf0VKlZ%Jr zOOb$5AB&x1OuG3b^1x!MFJh& zfbSeX-0F*IGiPW(xwYS3_+IDUJYYco+(a1CA)Qmnm!P2C*M&JE9+3I9^Cl9=EY{x~ zwvR!}2D$`cM2Lm1k_(kh{hm1NQ~Rzsw@f#(@qS!XVs-!vH5}&0m%*IzSQZ?JWnN%2 z!;eMS@v!WGGkP>ctTpj!r&!He*cUx?Y8Rtrr$W<$2~wUgj7<#d=J2ekgOpS;TN102 zfJwo5a(b*q`zD~a_k2PfaZC924J_DTF#lUJl!9a}PG#lzoVY-h=Hp>o)~jf!3B(Ws zDu8)e8=?DcrN@oF+*A$Sr}wzx%xfjPgBV}mhH_f1RB`%&pA@76s(5{=PGB<()+2LT zmdH8yf88KiKu&~|eCh!;JQz+sLf7tN%=;sGNgVZ;Jw!}3#J(>jn;1SZ<@UR{x?|sh zN4^c3jdIcMwr;w6d`Ig6?qYzFg9Gy-CccYDobOHUC#a(Hr#6dv3}buhz9)IWO~Tuj1}7|E*7o$R*plA=sjLugvgq~ zf*K1TyJ>WGa`4W^X5J3?ESD9!tV#(sgmEH_Ktr2);RFA(T^@C%2!?thIMfNZ%HuZv zYBRq3p+#g1^V6lbWW6vV7Fne*5PEVUd^3vzL{Y5`(Q^VdLJ2pICN@+vjUaQ};LQ|y zt^zJv1#N1mfjP54^cWU<`%Z7DPS{fEK5*XHEsNy?ecvC06s3#T#71Jh^Qh_3l&RBF zrG)I%gpvPnlIj>ENsTJ(3^8C<&m;l}i_REq4c#Ks*rYPzT@qIV-D%ok6Hf}|UTuWf z<%<)4fQv@7-l+lDNFACDqlqCViKsmPC}ym*E@l-jL`8dJSUBUNehb7r{M&l4sBdms z!d^nub0mxV%>~5$)&k;wb1O~U6Bli6X{;-GX%_Ft#6d+PLCp0n2tj3*KlQCK|@SZ5mR0oNR!25r5 z>t2d7YnQLau2wKhu4k-!yC&l(-cGzMBLPfl!XWJp1_9^^lOZgb;HM0!!z4Ty8YdFN zO#8$3?==traisjR=AP z|1fypZ|f!uq^kr`BpMfS>8hVT#9an_QyjpGTE<#7PCv*Q3bNn^&=`kQb~x~};?F;Y znL7DAg#WV|@H?ZLq$bqz3Fjrl2=kIlBRibUIJaz-OM>j=)sa+2cP&KFILxS#hL&zQ z(}c$uB%T6eyPldB6vw=IqekVzJfj^8!*bN$MeXDV2C})gO_8 z5vz*r5~2xOZl23~Be2ob0uJZ^OKa@MSi#Mxptb_G@1&!s!1^Yi9svRYq%R`Stu;xj z;Z>~i(v9!?C~X1X#jxJWa&pL5veAe}qB$V}#&%XA{z!{D?hF6N%ja+PnG6TLZfhwR zw@dBu&1f<#Ark;M6x*ZG6V(CpK)qTO_`O`O(KjB%{12WY+_F=z3a3(AE?4pYx+pu# z<+}49qWnbl&-_f$i4ss5`Jfie$OqZZ&St#l#)$CyZ}KUT~i-ERK4R2!>~q&#*{X6F0-DXnO+z3x+Pr^wx9& zwM_6DsS?a1{b8qjc0(W`aXP?V%E^T>@HJ5*e|J$DgI?)bG-jJ6HZVK=Z4s>XHx(VmKx!IgsGc zhOrn@P@X*A&o1zwURZW6MWTjxKnbH-E`}p$;|0KmR)6logwygd7{%GN$7j|cxA<}I z^uyt&Q_(p1S^U^IK5iVG{=6<^{5#=a`3wsWyL18cXWXP7Om3hh1mfe)@zw_@)7aeG z-#h&o8YFi2P7iiYPQ>ovv1o{+#_{Ri)~Ef(u{ip4d~|rSQv`kAN5p)BFrV&c)P+FW zjz96by+G39XXx|*uRJ_PqFGuBATBqBdn2BfIvq@<>L2?=C zxCJsClv>?$(58zQqfs`ay`6Np3`uCKWccm`$m_qKdgD%720gea=E>-*CRk`Uull*T zDWDzhw_#d$(491gqb4+$6*<~v>XOq4^at+e^Tl_5e>AyicEUH(y^&A2?hnt;?f8k1 zwucL}Gjz}-RWb^qD1*d!qme)85RO|iZ~*>|g^a-?0I;Cs+?1uLZiwV3!QVf{na zDLRF~JDtb`d?Oi-umVFU!0N8_`mE=j2d_&7fs5A>EJaJN5eZC*mU7Sud3Zsze_hHa zJFxIdYqxRQ*k_%eGfW2;FbnrUEc@4OpE^9N)@pKBF5*3mg5xDAtoy( zLpGE0&fjzpbkA`+kjx*iThp_%0+}MnW=ZI2@wO7T9Pt)cF2@$ovbpnk$A{x-^^z{Y z!eBRiKMFeYab9{8ZXLD~UTB9i00l}q-g$ov6Y1XJ0Xm@X?f#tec#)cjioDkpuW-Ha zujSEvgD%*-UmSPkH)W{7mSSKW_?@TohVU%c$Dp4DOchE%kj-9qg43rY6H2z>89h*7 zSgyB74thB~1%--!e-+ibq4rFSX2?#B`awUo_`}D7yp~Gtb!sKEjm@pi2LG3}%5cQz zX3zI7n?vQ*ZxmiFFRv``Zf{mLXOvAYS57Y1nx4aqbkzj?WISntHkVMkzOqu;-CeFU zR#&#QL(^E?Lv>}+9GzX$yatkbcsU&H9V3|#AP|a$2XS?PuyHHtUxmMf8Y8opk)es9P%UDu1 z^_}f%d3z^`dj7TF=Ej3$9r)fjp**67Xu{fW8&O)WEm!Kb+HQTjUW0%17vC@MCe=Vv zusJk+Ck^!6#%iUpo7Ou2nmkFH{qCUeT{kcN#7+h@b~asSrM%qOt*&n2ujtv?n#HUz zB_?9EQzNo%R_f(g2Z!Re8H(GclLQ6&vElA)m&=PlaKr22x`Q)R%zO~q!x5;%pE=op zy|cNqy;)rZZsp!^w-&;;n$+Umm0D$|;cTsJZB}9|mjtDj1f{~`p}y@p(0|qCdSe-X zt;Si5H0;PN!;H8ev~st1p&wXA9US^R9Cw-%X;IwlqMo`pI2*35@eA7?Tj@Uam&A9ZpLVv6Dw?=>KGUa&Z^waSH z70vTO34QWHlMvngH|q9qa|sk~L?{+%H>sVjHjypd7WaN_aS{J7fqbN9=)JVMaOa2> z!Vg*$H6nbs8oqPXyD}wh9yboQK0I|>s`u!KIH4mF1HxO4{r#UZjqUBH#<8A6Z{wuW zycRf2LYKcP{1uX1Foy|Ig4*~5JSF#q^;Wih-W`rNq*S6tluCh9 zN1jl>KAn8PpJjnhKW%+@4^MgCO@0VkxEC5HKHiY47B!*jKa18p_#BoYOO8`pUUkbW zt8Qhv;?$khTGhpUv(=RvtOx5W%eYvsRowdO>Poc^E39f6|5aA2wdLAM6&72oPQ`Io z>y_2j3d8*PX@7g~hmVJk49jeMoz31`Y+)lrUq|ydOV6!=Iv4lG|8&NE=l% z657g$(wM;R+TPj9Y=1h+?CoN=Z6Ct~BisHZI;{RAjhWwssJTzkn6K^g@bZa1DgHm$ znNQ{cG~53NU4H7e|4+62;{Wq3pBMk17yq9Z|DT2Zf5>wO4QN4vN6#(_%^8k9_x0sD z@+KE})l|xB)B{Qwr7`6_4(EUx5_9uuPsd{)R%o5>IA?6ZV;)s)PI^xFu#Q}_xeIz( zvuVxeMGzJtq#~XOVSPofjl3POp(#P?wYoz`ZFK+6nP|R|^vvQZ94u@_Te?$sD|-_> zQ43lLW>333VkBchVjk(&!q}W1|J*#@Ir+4IiV-#og7uod-*1K>qXzNat0^7<=zatP zbu{H$iL_=ij%#a&-{&;-4*91*I@MKQQbyI7<4>B38ge-a04O%Axw^n*kz_?k^hlVie4m_ zqxB9tJ|tmBexB*Y&brrrjMpe}Mxh|QBq%C_X>*FigaIW+g(CfLhW=mDNcbonbB_LB zc4}o)|92tZi~j#CpKK%GSw%<%B9o!0e2yrMGnwn#<;JqpSS{D?keROf=rxqdyuIbn zeR~I|Y)ueoSrvC1L8dbuiFPn9X0+_ZAoH^3|BHTRjsJGPgKoc1G5(ipwe;~{ajWt1 zUwIk-&++;8o6!k*T%JZF|AtW-eD+2ncgx3Xg!@J;jfcISOqS;UyvW^gvChy(3F3(F z2E!3ONk|M7PXu^_NydROUJ-9wqI_L;#EO^};8$&hf3-G5F%WM9{2Qtf@Br#atx|Iv zEAY44SZO#l*M;wDyFg2@&@q#4`9LzFbo2g$u3xDRxf3>K6OdWINKS+DmlK+mg{IdRg zmQQxS8;r~api_@z&ZU2|glBz>#4E4IiMQcT6x%4^;kjTW|CdVsFEy1+2P3aLM%hn~ zSOO(Jh5)Ta=VjeUSA!7VtYSyHvbe6L@4f1219y zS?6r4V#R@9_(Eff=$9f}a7_JS&O@!gpQrrHU;ptw&134AYyYj-_8-S_ zUhF^5@o4Q~IX?0IpSQQ-VCTo}y{%I^xgm~sj&>TS z6n`af>10G1Gi;&CbaMJBOvDWAzAv!w-pS7Crm-ayEg)C{%Q^LeQ_mO4hH;yasL2*X z`bq8dRhgW)hyV0!rWt1O6ATn9=G=CR3jEzO3jf zoLSi%54V1Cp)@C7E2Fixl5w%IL^0K3_06O)h+#JJHdYf^iG#^&dWAnIrGd|G^t_4B zmFRg3pR3XHHa^#)=N){mN6)*jGv6uf*2LADj0;r&z^&Kt0BgWq{LVO-SO;L3=mHQ- zB#T1v3P%IBi+*L`J^%RI={)o2|CML(|A_7Xy!d}S(X;y!8d3lh>zsuVb->_x?NT^I@P%~mdzTm zvN|;54ZEyjoSHlSY1W)rHCF2`*3h>taecehgtcvfcOA!gi%4sOayd288n)kTY+@x@ zT0}vOMZAkZY;NFr7dsWxHa0Vx8+eQ37gU`V82^uU0G%`bt8x9`aoiXC-?MxY{J)>b z0Ql*C2Eeaq0sQnAvH*TX6X11d1H4W*0>&(Wn(=I^Tim7#THL0l#cirt+@^CZZslu| z+x&%3Zlx;t3!gxu2>ybn#^%YKJ0r0i;{|CANe8nwyoUy4K*;oLa8=0_h$Clo?4B50dp?7zD z}1-$lz`P6PLey^{6#g{X01&6_V?Ew{Qt3t{CB_f{*UWa zE3y5b+ROgWvwYC*dwsj=y5+{o_DZ8(c1%lWrdEUZ%g*YS>n^*StJ_<(RXn#=b{e%Z zl-gc}e=C)8#V!ZSLV&yDI$KWJU3F`l%gzpTHI#C&L}LZZCf9{IR;%?o*RoTsl<(|w zfXkSr0pLJ=z`t&Jb9uA2yR}u_fhH_FD|pe0+gL6)cB%kmb)}X7LeE41S0aG5O4;4q zL0}1m-Lk}Uq0&{mG?RSSMLu^n%c~UtQfX8H*k-xB14P{dFgx{_Z*5ez0(mM>JrG}& z-l?pVsr*V(IY4)L6%gCm!lPBo71!NfDZ{_yysOUgvWu6=l#_FC-!=dVr@XyWDMMdw zxlRRt?QHL^n!I2ZTE;>S^vM?d*i3_8dkFm6!tmXP;O{Pu|Ml%oWvg5%FE8&xPd0!7 zu5W=OV2Is`Kbu^D9jK!20Y-rOUA;&`0c_{8C=Q9|$IpEIzw*WX zzua4hzEZAL(V5}Trc5cXlvm4~!im?nn>)MP zyRJh?k&P$VXlFp4gZARE%SL%C$#;U!0+Z*&*CxTg^=EGUhevyV%^m-h1pn`P<;DN& zSw0E&-=pKh_s5Nox0%er&X4f0#Q}Wje2q#ur)bR+-%Jg>E141|b%uCHsQwt3j{qis zO8Xej8Pnt?LZ6Q0KHSbfKQ*MwCW<1mslqqIr7MIoLOO7UCEYnCgVd6hIVB0(s4V|) zTwjrqn1yW#i6@Iy_}&G!Jip%w3k3@oI>8G;LRxbU354-m49xZpq;T63fEhik^$c$p zIx_mB+#6szG41is$4~pTqlk`on60tB9Yu`9%Z3D#ja+agEO?aL4)V?@3pifQ#5)c2 zh&vGUgLfg4vZ&S~W@M`g6n$Av>6ZAYuxF z9#J%cE>S)?J=x#e+JRs4AjQ$)5mk!i?jQ}fRn>B)nF&V@$Xf%l=(N~o;L3O>Ya*&s2cMELFf%fnCTErPll{VLd2RSd zW(!K__+E#eu5TUrdmM(334evuqky;+BnEE@6OLOESuY!+4oSDHwcsH|d^EBk(iwHp zEkU8zfYzPa=2(W-ybNtCLk0em zg=Im3+T<5Iy{e4~H*|X~!-$U8tP#s#14?WqCAO`^r1pI6$?oM7`z)~k|K-pBEGNW& zecAtcmd}g-|Fir5e{rAw`+R1`f7W93Kck1`V#-=Sw3>CFvn7ayfsmQ zBvd7t$(3$aA!mkLfd}iQMp2Pth+dP-xW(wO6CMC>g!a=;rT}ykf8=1;IR6~Ic_@qg zO>#p1R$1K)dWBYG{MlPVlVNbwi46+FM|d!@qzXe;kTt55itfkn2`a%K;LpIJpw#lW z?)*{-sqniR6xdV;@L~6oFqyIaeLT_fVY^&0>b5V*FGYHZtbv5MQY1h~nC-hTQLmmu z=TeyM5G)E-rz|j@0ZgBqFVuSv2N+8P<*AMeC0KC8>k|9)yvCf}0jlXxnrl~SVWaT9 ztA2@MrlS3>YrmJZ-#D{GPhXqgUq0q%zW!HxhV$Pq`rp_3B%l8#^9ven0vD|lVz;q> zvO~_`t=n?>F3N+3o`gJ(mgVHrW+E8KQ%UnRl}9>`c7MWGWIb}k>4)RPANO|o)VS`J zo=Nfz9fAJUy%y}35xGRheAf|$w=APqRD~x$?wxLZ5U0nV5L>#6SDb9K9VmuK6zhV6 znpa_dL@J@%`<5?xfK^f(1(-*?SF;V zqdOybzXO`dH?eU39slggZ%;DvTOh-THT)YUvD5AveT9iVKM2Gc{>^+R-pXGxd@%ii z(U=iJkGV|In<>o>-AqqQtW&abM~W(`ETdl64&AKcHIoHb3lDuOBR=2COOxqU+Z#te z2G>2Cj4=ys9@kjSxJI)#zvZ8?3t!iC;eg&48MCeAUdgE zcaruPupeerkVC5=k?QabKPW;nIc;DtUf(sbrQcW{4sv_ z@aj(a3aD{INs~zr-(A8FAIhOJN_E_d|7`au2;80Q*~D7^Qd02W_cLGrTmIty-<5ho z{IA-J{C|#5qW;IbnS5&In0CWbHvG(kHBxTTX2$0J_qds+l1e496dsX9ea?7@y;8+M zZ-j;T(Wjrb=nci;k!q=)j;f<7!f}3%4o?K9@S&a%V3ib6^GlxCk$aNV06;(7<`Y3B zJoS8?RZtya*QJ5r9$bREyUW4d-Q5Z9?j9h)H3WBecemgWENF0dIX!&e{8Mu^(^cKq zZ&z2pvi91~y6bW2D9j5ju%0)l_R2&zfK~t@h6^xyw2vhYD@{h>i5=&|8$6@XYp4VRX(C9x`%e$f@Jee zU7j0|u=--VE9y6E?+^EF6c)7LX4sv62*BKE;Ebv3lPU*<2u>pH>*|uu8h?d+NCh<> ze&E3VNH4QFy=&L-*WVl8Q-S|A`n&U~DWy@IgtlD`NH(5RuY3OcERnKv-HjFu9@)vP$R7Nj8FF%mk--AtZ0spPz0({3MNUHSes zLtQ`U)817}jUwrA;kblse%`(zU_1JWHq^?CZ{i`JT)%Se0r&4FNs$TX!O`jwlzV`o zV0YK3=3b%XuoSWLX?89!q2o}2OS4sInuw<|#>I8RY4Y(W4I4v_!g3S8d$676ph*8z4j_q$3y&&Qraa2acxSFAa-TAXNZFnf@q&lPq*6u^|Nmqa5t5Lu2 zD^@bKTKa*T|F(ZV&2*RUc3dAsi9*(@)YL>+arncIVloE>-KsW_2yPLov>^<1w@Sld z@=xsk{uUUsHK>LM{&!LMxF|QZM>UwZwP#OGa0oeI8(1}0kG=L-)0m+#IwY&rh`Mh=V1c!Wj9L!;@_=%JZL%e7OMW}%OQ)BKVAI(jJsdU7SStj^b={Tap{$23Mc?g3c8w%eQg@8s9<%62sONKi zxUm$F*)`LH;4MD-Kj`xU^H4){u+1ct_)dSKbs--XRON)JTRPrVQ&)TrnCK8~(U`D_ zFuDGR#xI||qgE>*5|kdeP19;Rbnk(zssq*P$c_!hNnOdLfAevH23PtYJ_ABgZ(a;+ zK%(3M6?nAKzb9j5GnMDUmq`Xl$mx-|n+kN*gF;kEX?p9g#-%TKC9nB$ir2F{e<*OE zjVs1(JgITRh1~cNzYrLLxNC0k$+EHMIcX+DVaW+Bb`hdyO{w+X3^&@_Z>{v!dU%Jt z7$vO)^`ZKee274)CvoqWy295_PL$4D)d;nqoKP#hN~B##)o-O;$iI8vX@tRHfqvs8 z2G89)V=TFM-PacOycyrRx&6J~%=|bzoQT{;f|@Y|0R3{UivQ|K#VbWDIY#cEI^2}{ zcofDl*#t35qu|UMdA=GC6m$rnziuwC5^iI07?596;eZHVg{O8uY!$4{wK3T{Sc^p= zc&|hm!00AUh2^hK?=U4>-jPqwn~j7}2r&zya82|oj3y|87jV%q!d;*z%7=H-V6RKM zBPHc8iu&D-geMNKVSTv7zvAioBep*?MMhD1ea^&;`L+rJxtw3U7JAiL)(fwq1LX~? zD6>pOhBM@>pyIj(y$*r64UcpPc}+MMcHr%z5WQobBH{ zML(EO*!JN>zfuxZP<}hu`r3T&sm;at<(7Z{rvdU#bB~xIe5*oy$k+gxgwy=BPx-`@0$BwAN?1g}|A)0Aa>yC!H=frl3-th#!2icwaj=y!Hgd2d`Qeu6JxSLah5ufEaPAS18)hs`N3G9|b|LEkgzGOik`?W7U+ltSQf#AfC--GcFT!e7t>Z1oA ztdIp!eU;jWgtHZ69GJ`y?m3GDRS%Q(K!Em*d;g+pE+nUw&G$ z1FymswFb^@Bk&YB?W*|80tJ2FT}(3eC+s$~Z+jHHwq6PT^CxZl)B&sR1x4ap+~=&- zxao1tUfE8_;H%1Q*E=ZvDG{Z*+M~Z#m?r-Qsn8%^VBFp#dGG6Yl`x|>&z|}~hP5m2 zgR`bS)C`mq(FX9Pt5Mkc3rJamlLlKK83MQ-YQaSDQTy`IhB0sap%>3;`ZFPGcU_PP z(m}@@utHgk&nwBVxO%@t7-_go&y-8{Ldc(qS{0PL!aPVfjS8L^l6L};euX%h8@7>| zA)_&J-to7W6{2H#VKmZmn2nX4-oQ+>dp%*`V1_9r$nA7qWRC4H1pXVW>^gCc;njr6 z5k^^F_8i&U;q{V$Tr@%N3Sel^-}>8$AlXrvV;&Pkc!jGw^;ydU_j93u?jLwocriFz z40|uNMr@@0f)S`D2m(py@ruVaUZ-(6vd4jDm&cN&VW+$j>cg(XGene!H>i7V(+o=Z zW(_Q7ooUHIGY_n476zPC4ru^%A2#ln(Kd=U_qt^L6KtGV4Q#qT4+FQl!YnVqM|r3K zV5tJ6Z&b9e8^iruH*H$y#H^|jaONI$N1aS3Ro0F<`H3=yLbb`OoE@h3I5Vi>#DR|U zMCuoRe1^&7(#2eJrs7WJUC!P(Hnlg7PWefg0cVyho?3!npUi(~6Hc zCvO4mLS>M5y8Ojqlj_z9pzL+gm8a@E3dhp+n=V?;_QTTid$-UB(#gS0PJ}e}D z2TX6WM2JM+A{gL8mK-XuvlkrEXuf+Q(b*@+8L)=_f`W}ESaQThu7g>_ILYv=9HY|X z!32$21~J_ReQ-?GU^Pz>s)MQgL(BD8=((=-s`gC{F%@5O?Qmh}=+j`9M%{?H_& z8Mla0G~0oN^=Qa@zjwpVDgg|rGTQ|eX=-2Zih4}V0SrqG=fKWD*5Cgsj;)3DUR#gQ zjyKt!3SU@5iYM?Uz13m<9Je)RHQM2Lub(JE1vUKmb@e@9-lBF)1Hs3H^f+~gH?Atx zs{IQpUtZ+*JUCLR{xA9rrcnDXEW;y2b|GJ{-i~0>N$F@w_Fn&kA77SjB~Z@42vT~# zM$sM^+$2#DmEDKFwsq#i3yj1b?ss-Q^UKYKI{J;pnM@D;n;kA2zq~{EjSQhK!JCz> z42LUBRj9*9D@Z<>ZMLh|+_iCCwyrle(Afyxo49kfWjU79y+AZwiJXC#wUhzAfpBFx zVPun`59|jVrs5eMuISn)Xb;o`3bxa>cMEe|3fV37f8JcJ!ZRS?2seF3X3n0^k;hBK zBV9meV`Ce@w4LU34+&JPoXt`#%@lmn`#v8YmyOPIhfd%n(8DK<{5Gq#rvLN%#WJ?> zE}1MPHZd78wtqyP?lNh`5_iV-uN9}uwp%NABAcO%%qT=D8^Q!z4F2o&U(I#Cjb!ch zKF8b8Q(C@&j!cR6ykHpJ1(>T^zT@u_Q~(K1ACY_UfLGylUA+95l9Ia2Qr&OXMOZf1 z&;Lj#X6bkdwZn^dD$zoq6U5+{Dmst|EZ@4*Ilt+1Gk??<1Cfq!qFF+Qa06e}xZn+a zLuQluOT|M$8)>4qYEGYAz!qa+N@5#?3LAR4BjOnx7-=NBn<)x;B6jYD0y6IP@Xzf1ihrPRXxbls5mUR}|n`RG3T4Vqes{Cq@)V{_?0 zm*&Uacn@-Ve-x1A=*n*jpn4EI$CV4wVI!2*>8q8qIkp!p#8;ZzN5oWy6gal4G3Pwj zLh+Tp&r(j~2qu=87=j%HuUSjzins z{vQtoAp1Bd;vJM35~y&jKR}xDORh~KpH#S;rMj(6R6!4hU0-`9lCVsw$AJ>jYy6w% z0-KcD;14#5UaGJ__HXtxdx5jJDrwdHiEPN@Hd)c8bdAtE74oZ}<&R0lNn%ozWa%$K zub=u^S@bgYr2Iz}ZxJ;4^2dv1I?*#Buhn@Y+`i`bpRk;hKZrFNj@X2^L5K0-(acQ@ znjaZ)__UEjRodW!Ktt2`8xin(3y9@Kp)qaTjNd-_zZAKVdqH}jX!PDET7H*(?=Mpl z`YV!t>|ieAL`zU<0k;mr8{IY?AS0@e<1R|Bz@V0}F^_R$_jwHRr!r63=;yGDvjHOV z?{r29e`!3lFaj5aB7;t5Lt4buY4~Je@0H^(biy(8784G5y=5N^oACNon50Z*8KpGe zSg=ly8{#*LlxuWsEE1XzG1Ercw7Hb5^#?et%XVfL^eu*6 zH+2j4k0do?0X9abw!mB0wjUpKLCb3evj=er1#E!HG(7NmeVzf0;&&p24m`ZIboCm@;J22c@Rdio9CXzq}&JLBHt|qu?FqP@3e?|H158K z7Uojs(1Rh2rE2L8)ryNc6?p5@=!khF^0WESNMvU8rDQBaODP2F)k(J%y;yrRlv6EL z^mBr>*hc{ntHN$rkr2D&eXI?^sW+T};AK zNTRJrCYq%@5V`j2GiQbTxbF6;;iN85Li@XI_n$NS3&h|WBeHkRuoYzPhY!A3_hsvj9A+e*P49i6y|)K0X#=Q!%u z#MuWN2LmX2u5Cb^M|g+2L5_5NJTcicF5Bs2Vu=JU03oj{X| zf-&`$G4iPIA2<5$VxS7c64m+`ixqb@dp#en_M!&+u^*N$aJs4UF~RH%Ywghu%c%8II_|Az zIvH0CjQddY)vH>C5ps0jFKMN5oj**RT}AwB4O6_7$>^;bj(hG~HG-<_AUW==>Ew4B zKhVWxH)w6W)Bo1ya=3D0e0=(U_ipIv-@Hw(!$ASPnr&WqZd zvs^>a>+|{W^<460pnr$=bCvP)_4C^Or0MI6-GRx0s?*)V*369m1^tn1>lEyE`uG}| zb(W9gje0MP6gR_d_8?SFYFy*21aXlVq9>b2Fr_$EQ>?WulvxFSk@KI2Y>GS3kGcf$ zIq&>8BW}$L!GH|7HzG?kecg{y&$2wu;aHDL9lBzAC}!Dw4ZS!Hnauyi%tM47u+$4r z717Mg_&qm%F?Q$Xs>)5($qRPyhumBm2cF8P{DtoC(AP{xU_G4|P&G6ROLqh({y78p z`aR>NCug6q$!AJe&e^Db90{Ww91Y%)eUq*7p*10?1D25yp16PdlX+Ju#eF#0we8q)8C9B_QG zTh8jQ4;m-O*z_UHV`%hSSlgPu(|r=x7z(AEFN|rtU>jvNDz4wNcwy*+KJI5)w14{u zBH%u2y$?``=R)N0Ab8K}Yt%}Kvrm4I;SgcstZ?)Nd41(rcu#G!!VAXRvrTFkGkWGD z`n_Z1ndDl&4ezfy)X|15JN$2pg&ptlBxUJG)1bG};M1!=-;07`;iu2k7{Lo>9qxO0 zL9Ax+hif+nzdjAoF&W>noD8~&Aa!epNnKL*H;u{Ph=hCfM62LFYF=xEl$gi=tTjh1 z+Ssy9Pm@tb6cGv-(o>k4^e+TAK>AMUmVdUys@Hm$>(${R5biJLR>-YpO54_mw9~(5 z@VVFA)!4!7V;aUwuX~|A`Obm~7A%>NL2B>l9~_p%WJ^TZ)n|K76e!GCht1ezy-3js z4;cEpQ&B=OFf1CL%|~-07|w6ys|lO97dtjXcx=w8Ogv6*FkCU+_|9$M3HuJF9Ye<= ztfAWBpxr)xbe<%r>_B1?qo-5-xydyyUW6XIk-}PZUon zEfRGsEcLu9%#iYn^GFy?1AODJ?W5hSHxPNT%ZMY6l_80o;Y2>C(kEYERDsFK3sqBf zLdua+==td|x@ZPwy7;AjvG&Kn2{c8@)WZ#Xm$19=O{!L2;kXVbuVk_N^qouzrBfDT zl9P8nhc|4%P^1g@*t6T-mu&PI;}qX^hLo&eb(iUs7Fl36(cIM0F$*-X392gJ zPD~98i07%Omne}LOQg#<%p+kjsETpxzRdi*@UsGn_$8oP7amZZu*)MDR@1>%&HKfxo;}cwawocBpN%=h{?yX);5#V){abLa+WYksOCke2rg97W;`v0jV%vqFr~~?$3Gnol z!r|6d6JkVhBzZ2F@Mo&yC%_wiPEX^WYSJ*y*XiLprfD;7uFt>l3w-R*biP!wgO^~^ zjRcjZHQdIg1hS{E$Ni+-kVti91Jh68T-k{tG#svNXabT9p4&n%*z7>Jlrl+rq1nD zT1$icA4^2cVkeYeoksJ(E-$;7mPM~wO9v<{q)>*dobm@}h_Kt>0$S5S8885kM zB3d))S{vDKm5VTyv6N|5S(C%p(*^JQIzJPg(j(>RSXtbBhTzQsC68i zeF=!>B{l+`dX-aeppVb=9ApK~>&*hJZ{Ce*fJ+j_*GuC`Q}@Ri@|Esun8uru0L7_< zaZdqDyd_7y2`DAHt+UOi(vm?I>+eBMvr9se>NA46#>>gr&X$UKVxBieH4CMQxm01@ z3l??8g@xy(lil4x)&hTY_*bQsKiaOh{N2G;>{093{2LEiV>=HT0vpUmKQ$Ntu=PR1 zyW{18v(sLx0%T{y4d4L2+tWV%+6gDUo;N)HAW8Jqc%t32w_Fd%VXplGBoZz17ZcLb z0RLY8besa^4pp-kK^^J;d$alRav$fZa#Elm@Rx}J$ge(pqHtR?{HS!>Kx2LuqE*RB zL6CT2gaNvn=VI&)=YrByFsq3Ok7W8L4OSTGN3X9wR)mL?}u~OeoE# zi4aNJOqdd(dX-m3H7_lO7dJOt4_bUVy;IJt!rD-^>=b1s16`-$mLJ{n=OJ~SfyhD|@ggV9B8>{Pk1^o> zD#artchzvOwXkY=ii4?W{lxUq?wQ_E*-f645-#C=!B#}waEh}Ack1u6vBclWm>p<% zwiOQ$Q;LfW6$v2N-ylN+qGt$cau3tWKSO0A#Dqat(NWAepGJ%wdcvX4M$xbm%R0G7 zv6`CHNafz{qlzX`)_7fF$m=lr4syzHcriLoeo`RyK!Gc9M-wJOgO#oId2d2X!;QE2 z3JuY2YBK*BX=E|y$ft1qh^s#8UtLRq-+34`@h}UUy;}H9{@o84FFq}-Yqt{8&x*Om zXvvO#rw3OO{A~HT2;KQ~1vbweXmPh(s5mA$Gl|p&>&55#O<0mNo5JXosP+z>ZVkgR zm;vFkj&uktzUMtU;;2TT#JqEm&tn&sP~ce^hR(#8z~X_*dgf@T=cpM$GsdBj8h6j0 zpxaQ~4!f#4ULzRUB%{DS+DRoYI+y)S!-TJ`=8sd+FDFNwTMzTpfAKqz4jB?O@uv7% zH-S7*sZiZS(+eEGndPh)5akxLZM00b_@3&&5|?48`?F^_UKQ-hKi(IyDTEu7^Y!8x zuIRtS-@(T%q`+4z97;AXy^(=8>k)$M1p`@urP|%R`Kav67_=ox?-s zXG$ee+^8^DNrm4GC_8DuAY-r~P|f4?A2`b}>N|>`Wr;pe^EniY*A`^; zN+GmmPC->x(`;hQ02ZFDcY`LbCwM4h9!=Y#tt&0rO9NZ~xf^|*w}ymty`~#h{sqO! zcIg}$i!!I9J!)<8-10;jxkH%u!7U>DT>~l5`90^wl@L^g;0ZT0l2yw<2yvG}X2x!eCN}PS+Zo#|Ol_vUZX}8f zvu(}wP@oz%SFQea2dXY~_z6o-;v*WGF-h8U>=ndn=*XsJINTTfX19>sHT8(!_wzXU zNlnO@jXHOQH>|KFEyH6s4!%JH*JPz$SVfShGL-eavic*N^dA;!%x6hSC4*A3Kct^4 z75}`?w%V;q#ec906$v(SRQWvev4bd5x_m37!o9X^Ets3BF1VuwDZH}xf*#-oyzZc2 zwFA7EUB;r7RZYB?8nSIWtdZ^QS79QO{8Vr(4bsY+n-J^Ox zlj5Qw;)FL~99e%5KkvcdZf9Q>r3aJh8--4?wzE!Xs3*~BX! zU?r}4h(eENDJlLKLz?i)Sq&2{8Qwg`8y3rGKyo6TaZ?T!LZtnBA6YKyT7 z-UveoLR%p#0mG^JdM}E63*U)i!>6OcSvp!9lh0)5U4X)RL4opT4;rnGw|E~;tasIH zvM~PW`#Ezz5(#b#a^=8l*A z1n`p5I)sp-i_k&%>e3Y4q0ND|AIT{jUrJmYOGO(5hvf1-i^W&Adg|kamMU5vk!^IH zJ4*V0-#PNOpC^UbJ#UuUD_`lrGDxO{RAkN8t1jpxw2HA%W{K&v$1AV2aLw)g9?7-c z^hMCo=|w6ewLnW!&L;Pz zny}^pso7*(^WFKxY0kN(X8U3FYuLGOo)9vUrqi9H-X9|UApmi6`1bRSCVjqz6j(d0 zOU;+1Ode?icVdG;%iUW|+r}9Ag(Bm(EYcF5RPsxnAdh9j`{f9y(vnodyYae?vDZ1! zy!H&dK2MzineU)RfTkX}oeCPodCcBzF=)nYz*Y3WXsrrJZ=YBC#p2-cpr;tKEsoS8 zH~LFC3-Q5nh;`mtUf&x`6?DJ zorILTs+5P#vROLu!wAU7oxcA2Vb^nS--h}zPq4-Qt_*%=IqFCTO1W==?OE#<@a!_M z_G0|>mM+bEGYq(VdWG_wXZBmhA`8+QAcld{0$-z>drw!6K=30jSE*pR3nKUxJD~Jnob6XYazhtYMs#`W%*j`lOHGlc0D$X0k%;-4qy^ZTa^{fxZFuf8$xk9a64=emFX0(-eiB26|3xh40b9K5`wr=0|QBn(1ja$3QVkJD^gTu+E95PD(#)4EVeZ2eF!z;D72j+=+U_EP0!f56 zVrrlrzAM*CMDrr$Mv)7A21g;E^-FzMQcrj}PMS5zmvv2*raa8}HZ zf7`5*Q?KKt_s{M4pjeJ%Ss;5gba&%ZjqMu%GBin z7fZ|kCNw~_R{R66C>8srmfIzB)MU4k2ocm%K*Bn-`;QAO4wGzD**PsxP|N!-Ea$>P zW+>P}tykobWWuH6@*hbxw>7PD5tDr!KjLk^-B14 zLunAl(!?=7W$aMTPn}C7g;t{XNG`miV+%Kgy{Ji|*hpbHu;P?;Ch!{mSUUY4_is>D ziKd(hpgUnG=ij-aZlJ{7%F`Ro=MDoVp*Ks6yWx3)fk5Rs6?RBn4!^{OSI z!jNCc=LlSbI0m)%#Fz!)0_okB5G<%>>Y9<)+1|B9XpP67mgv!R59VK0U1~Lw`Vnka zhja=)o#*s-RXGf5OSlT?>78V3Du_Lb|10z{s~;mA$=WsNdZGxjmbI@(l}IP;co`Ui zN_P2;Zf)Am%*Z7P#6+)`}W&I+rU2Ecw1bxJfk5nnT?xO%_qX`e@zo zTGBZZH;cdhyJq7=MaGhA#`#}8h`?FoTajzDzt_<;6^d3N4T9cjtC^pVC_u3jHbzUF zqe^%DqcXcGq`w@SYN|{e|3)uk2OEVgYk|zbQcnXU%fb^ZZ>HEJ%TI%e$+4#92F)(|Q!uM1x zT%5xgCT-g5m-)7W&BNPGK5FWNq{wX67Cg=#*~XM<0o>ja$Iz- zlc~{LhR<>+?M^gWCf+JPQsi=Wdy3Y4?;$C&YqQ1{kxv`^^|kSnES~h2{8LNWfr~30 zFKN%AEJT9tN3Y=3S@lBBf2*d+?6Lu0EHKkK0!1Z{y9avu>RuTQXM;Zh^7;&sBypcJ zO_ymSUTbBD7@9;?%<=XLV?DIw7ObFrnA9(whZjn)y4h}R$xiZIlIUPXIcqe@NzR~_ z7KBWg5t}liDavAZ;}KhlYT>Ru_~z}}xdB)y&C9$wKB4mxNHasUrozb2Fo@vXP9#a$ zZ(detR63-FeLPeR33B&VV>SDpu@y;zVb$tT?io+7NC-~0ttf>gESmO9@$vVr5Az2R^fn9bz}uNFYyW4q`Nq$5bbdZr0%Lvk~fGnu&B@+SslXQ1u2k@5V+nd7Ms zrY6IaImy3k+YBcKNAM6h9SZ8l-&bz$JDQiS5F1u+EiO`=mi%N{0?N86d5 zPo%;!2Gzc?rxQTUKL&!Sgt%?`#Kg@6#g=~e)+lZbs>S4ef8uuq^+aW=Yd} zlf^b@Kx94%Rr`$8th{b-P75F`6wWZpHE|jr`Al8H=)cy*0UEm3)F5g7jGF2 z=%1iagq_^u!QYo7O9mU|K{QkqQnzt}{+<_8N?sG|=bX0n3nGw7xX`}%8zlHHaFr0w zzYgpzrip4TWYJT_i!C#cT73EYt87%DyOQldIC8*9KPuCY08zO<-!$+v7pW*}RPoEh ztbH_SMD5$}k>I9;t-tR6ZJ6gwKmo}cIq}<67j+sMfYS7MD1D&)@;MNHV=*DDvHiO6 z!@8p>>457U@M4i2CADx}Xn^}rIK*ohL{}VOyU?cLtvu)8Lxk&=Q`CA%bAAP#P{^{d zbY0z{=bz*%jn0{MjCjKvJhHmadj>(EpFnKAMZYGHrsk!FZ?h99#CG8`Q+Z0>#t@~+ zmn56i#4#@FMOFY3jY?9_Nj+4eYQ^$RT_$$;`gL()&dWF?kM<0m{ry?}C7k^YG>`4M zegp^t%GGM?&hMbqKPQY};Q!WDu^s^0OuVs8H+Y3jkeAvOe7l`tO+kyHu>5(=+{4skpQI>v%=)DAT;>2}6d&>ZFD8Shgh4+y#3r%$X0}xS zqZ9TkH~)BQkyGdTA3M+F5z>)T>Qz`n&0r=@7Z+;w+E)#gj9GVS`{FM#wV@Id3iu?S z-YgeQ?w3+d=vL7mkS56J2)G(qGWIQC38qXlivMv9a;d0(SBGVOI1UY}ndV7>aBJpU z5;l?2L@byZ+IC$Fgwq{KQ?lS&>aq4Gb9wrHmQxDtg&z`WaA~_O3wAorUI^vQkky-P z!Q8zr2d~YRrMIUQ>3sl+NjKu@OaEoh=1Tzu4?fAu$W@4cOd7pmd^S;SZIrau>wJ-^ zju{=pg!DJn@~hx~pLHR5B$O19cM(i41QrIl-W;%3}Jg z;L}}qi5p^O4T~U8sN*e*`^JW*^S-e-KeFyG2rO{L(H+YOo{UlenScPjPWd zjX+0}9@x;#MT*@r!+ej^-X+2`RCW5YN;NJPUv~5tqSm6cvi$o{vE>Ur3mvSt*?b%e zK>(zuny3%kk@;C?1oisFK9MW7iu@E^6+Nn1c!)lRM$AR@#IE~s>$LbzYe63Cz+@G! ztIJ=8Z1FC_S<(+6{ryZOYHmPX9dij{ZhOG=uCV;KQ#OT=Rc3b1a>t6bKDk3r6=tjb zDEm-FG}zlu!@;3VTlZ&-tRu-)W+f|`-v#4vPaD$(i5XCF<(pw?j}v!MiGC%XADE=) zoMw)-57O%5pRVnuW>u>g)I=!LX*uB(6ib)Tj(C<#j=T_2R~uBCob?CMK`ds`C?v%Z z%TTgoJ5UT_e>oVW{`np9-oId+ugo#wu?{htO<^pWJ#abIFaDnFj;Fu!DNAL1$LRVh zOmj$8v`J4qi?!2HoE*plB+862E`)nL(LWCsOrY}ZW6m^`gW%9?NDx!nB$leMoqVznw%=$)ijzciM=V+O)_gIqy2)ll!T2HFLR^^G%NjAGLP+q>X}cgV4fQxc*XE}YigQzY>&LLVn=3+g!YqXLW2sVHO>;yv2m zi#Bi2m~dd-@1y5YMH#r-D-;p@{9-4Rqb`ffak3zCOkyG5IX^_Z)s7_UTGq;@$#k<} z@Z}F849|e&J(3Bsn_vzSru2na zo!EYg%j#d7xJW0|(826Y;f%EU^MFip+CLIzV!W%8C^9ZZ*y~YPPtZ(gb2CrU&{s?m zY_S$eNfKU?75v{gB*zR?`h+DgZS;b_u(|BiqRWzN!wUZT)G#Wmk=gi!b=jQeZ^vKW z7JHl9bRT}#7ld*fA;+;h2o4V-QZI zU%iGb88`TH<{T8uVjEAPW_b`*Xe4F#2}e(BWF9TgV6-h9*0a zao{L4s_|QTi9IH(xGvlymhLd5vF6t5QiRH^a0u&KbpFi1J!wnEC*)#8zYIjzla-{3 z$CD_cU4YFv^sGUeuKEN$h&XB6+F1OS?~D%fspAWvneb%*(b0{y@R={{&iu~<8 z&L8mr_<6IXd_O)87?v+2%SsIl97F)PM$!mR9(3urVYRb44Fh?t?>G&X2vKQW2&c&GWCf@F)KTG?zC zn2q2g;Ho-mxo7(hqePB?UG_~+ldoJ|tH_iNM$Nk1_L6d`Bb^RX89>AK&J*l!_(X1L zMd{h~FAp4(7&AL=SqF6s`{P$vTM8T199~eqBG`f_lfN6$Rf%2x6f2^EEv&z`GL_S# zLA?GD`ROJ7Laq5u&-;w1NdosTXXec6U%+0lOBLUX>Cv9sizfW(SFDX1Pb_&^|pq50a;2g9#dX)j1`3 zljt^iE!8FtkMwRC8bRPZFOS~d-e~=;SZV7=->B{{_f5V`ss-G|X~DptA?5nF#8x+m z!!y94N^A2qsB-D#47~04JoOgD0c=kJJh?zEMY`tC6IE+ph1d54S;M-`z{g!o_vB0e znZ_X%inZirRf)+rnhrnvw;=EJ0b;A|$_caC(T*>$S0l6XHy}18GCC+fJ5i@l#+~{dW)>(Tvrena=HSJ~F6J=I z5kz59P=C3*by1MHw%*Cc>GoneSto~PDk8#U#V||{X$Ttm@Y1^YGB_!{{?SBb9i2-c z_VnE?IuK(}F}9TsGJ*!O#C%Ab3=GkjNK9I#y>NKs4HQ zKRE>ou{_No%@tBd*LvTtM&C0?EE(ET4lF?Xx84p-W1VhI zCRSpetyVyyMc67BPZH!#w<-7+rB-6w|KoJdyWa3x%(|+ zcobuiyKT{oL)NKbdCs{-)B3_sX<=a^bHOa+z_Y-r_jNsH|D8Q8p%vZ=kl zFjnd*a;~nhjg8ncup>6*zm+gq?T~9{XE9krvt#{p182{7(v?~d&HsI)v|pDJFxyYb z`jOS$9vh2o#*`NFor#gMmLlZ+fc9U4oQZvD)^27Y@)jahgaqm5GU@HVK0fXPzZOIR z_Tu*;Vj(g;8HasEWV9u=er46(^rD7siT6EYOqCG=)mG)2IaN3-4^lVmNA05`xqTqo zalXh3Awl?P{wJAgOBRQ#mO*=1^s=H_j86oVn)R~}hnnb*5zO%F`OfPXY}|0>v>!e) z%xuIAJCE|$*a}l&UN+E4w-W9^9*=aoj&D%jzQ%%=B=Z}qzqowbT)Bw6N)m14b7S~I z7?MSMLw+6+b>dlg+H|Wj<3ZMYE5Ce$k-dGRjaIW z{4m4YH9q}k7JUG$UV|FndygLgYN2zG?iuq5TG1(5;U6G`(g-TVaTLCrjf_o0C){<1 z*+c>|KR}n9hUhnA!QqGOb_$enozw^htntdDiWs4!OKTT)+EQ4**DiCbod$V0n74qp zM@xNB_Y6Uocl`hMZeK{BAKN}5dAu!vch+%9?X}YxCYz65y9>L+Ucfs$r-Snw8{1nw zfnHDUAm7fQJ5SX3jzVi`IFD;*RP$!-;6y3Ix>~>U8HAF=raV-PM|^r>51sknk{nk( zMXa!o(=n`4>VL()ON2{Y-BZCEJufcAFKEyx4I0YyVi57(7X+P1Zu#;LaS2}wRfe^2 zD`0#1`koyBJO1*GDl)}$n4DnmEpdzZJVXxty?6Gjij$lhtMqS-^h*717=_S~t6U4( zif*6BeTYh-z?+NV{>GO$ZRyvj?MtD}?U$guyq=BM(ZKiP&cVTVZD|a%_qDje?9KU& z?F1u`pU@)@0#UBJgp^tn*8U(a=$zuh$ZO z{x1N@KsLX$lRok1b>RJU_Id6Re z(-*2NuP#@AmqpDZ|KZ=eZDR`gzgF9r$^ZNK_{X1VoOjSh&iRiG7;M-6+o;U^zxVQ) z`G05r-fZ)O6qRv3jj^Y?!e&~FJV&7K2#cM9V{q9>?2Of)5qO43ql=&^I%$_Lo z3om2N1*?KP(YN()*-_v*eeD~=H`t}m0l$xo?M~8d zWf4;XvB)moE=Ke9c?p=Jf}g^&)jvOiQQKCJ@COS$p&q{IjaF-A^>uw!f8AIUU!T#j zVDbGe;Um63p^M|hbg#!ixMv+$U@H`(52kwf0DVudQ#0??-r_0DXH+Q8nWG z_v2oZ1hbf()IS^_Voeo;Ky13RV_vJX@5dnBKT|XQ-qR! zjQ=e_lqW@ksXS8 ziFFs`tTr9^z=TDo^>JIPVh?!bNK%k7tVI1RsS9!oQtJfkQN)^pid2U#5tdm_vxF7t zC-bPb1>Rb6jLRS?f(U??C{Y3mKvrYxs|5hAuNDWmu@=Ps0F0Ibt>LNYLahl^Ef1n7 zRS=|5>heH}QUyVhR+tBo3KhkXsh_!+va%C_FN8HKT9g=|o#xU4$`t1}P^b&=6qG6s z67=!{AfZ%2kf`400X!Ovi}I+j5%K_vQUyUOshbB>l`9C=qj^d5Q6BS?cbpHBM)MR; z)!1M&Q4tHHQCzIGF-usp6_tr>rQk3ysNPsWZ9#71CQ8~>yvQl?xDwJ7Ce=@3!xqvl zUW4lpoV-p`yqKeLu~#ws&MBg_Vy>5}%W!4)%$Z=Wh!K2)N3jJuSM8Rplc9HSyC|x0 z(Pt?<=9`xoLQ6V7?)2#V3ZZPP6MSfP(kc!q7p`8x>8uCMQU@~`muZoVbAyNkIF^+_ z{3IvhS8oZ%tu~`trP$ax1CI)(NXe-ORTKvznNAp#kv?pc#ZaJP+|- z%{)?c!XrjHI*0n|^|Sr@(fc>zA0=wFKo-Du3z5?7VE%vaTkx$E@`wV=?!r83I|mK*|fsxxmwl50#JZO;AQXaCDsv zT2OW*)+_BCPq)lCQ20)KXQIT0N9ysYn|{>#3xyYk_y5zuveUMacm8Y5jsL3Es+HOO z@AvYV?f=jA|7ZLEh3|j&#n#W~?Yhs=x$ktb?Tb>O&3*Bf zHrsciZ~xW%mTBay5$w~q{~EB(`1E@XO6h`1MYNFp8!8p%rFq-~*@7gSt@@!)aQ#>3 zbnc*y-1FZXsrbM3jamNZd-=@P|JnLKTmL6n|Hauqf23bgMPNkMHXgp?zF5Z})=Mty zDIaRU$L*G-omXjHTUDfs;j!a86;TVbmGUq5$yonINb4Q6k+c4<*H&w(^?z-){@=@I zw*Jr7|JnLKZT!E{25c9BeKOzH6{a}?Fm=Gc445@ha5^+s#?k3*Y8gA15v<0Fc3SmO zU+?QU^!ec`*_L3Q^|)!wISg1@x3UM=+Wt}39IThoK4iF(zj za*vT48l6Q26-dkLqgKl5xS-vzUmJX=A9)R#FmpX?h7r3`bH4rVkmOVW3As-#F+lj}Wu@ge)7h8Jim!BE~y4Lg|d=WJA6eQXg zDv7JhbuoYin@z4R3bYGjSg>TM6c;xQJY*pIb26-h#xP1(Npld@Fb@pLiHS|eW#t4o z1XKi&?IK0&E<8MnMuTg?HF7Q;VQ$G`ip90?P{r$XU%@tezp-Y$#|4rVP|jifUOaHG zz;*dsVkNRq4(+s)-K2*p_%C93j^E1;yT?mabsLSv_@aIBBMzjioY|Pa-zRAQ@#IRk zY$MbDtHS@**PZ>}%35t^|J}=HX8+CXznT3viT~H6ZJSTog6b4_zKO__!a1+_&T`() zv-Msjb}MoU-LW_6QQv(6D}!Z)CZoGCN~H>{4)5xK_&RWt(naWQLHbIHl}fs8nI8zZ zSSoj3IT>-2a2Iv3e~*))FhhoS0uT3}B{&tmcp!%-TDTO7l752sN&)rG@t>XOl8zV3 zp5wEaQGrxE++r7ncQ}xzT})A~w%V<&aCsn8m`UP9`L4M>D**3pG64COg2zY|0;rlDBxC;!=WaFLBKY`&Up9KN0lM&=@bty3xExts_ zS#F|umhq~{%#`h6sLn6v1=NgWxU?sth5=gKi5?)s^f)b1RsaIfkGR4yDl4ELIv>ld z`y~}xtB;8Q{g-7VQX0CrddDDPH^IQ#J->sF^D)~ z(6w36D}S`>ubqsVr$OOk2^qQS3Ni$QQ@-@cmR@(ePTj#G6&8U1#DeBn3=uL%3UaR- zI@emsusP_E5w#n^gJBHZWjpE|rO#D|gcH6Tv9S?zhtB_mG)YT~9EqbDWqYYCM>c&f zOZGY#7L`N@=36FdY4Z*rZ}uI8H4>rBJ1hv7YD5sL9KCvXa3E@ZS!pX^iZNDlgFWNI zf(r=I9Xjl4_sSI)1SMZyP_bzQhBGJxQDDU|_Yyx_e2{8ZOngW!?#qgg%o(;o9lW*J zux3ed5mU6?TgV_HaRE(?Db%jQtpo}itt^2eZ57K-xod$!z+Hi2bCXYqaI3*DMEEM& zX(?XDvx=VDQwovvOr-gy+wzNwRO^K(gD<>&&z{3_T<%>HC^n;=Q;h=Isi0?zh1<_Q z8KYlB5tw#W&y(wND09|aQL1F-wRjLd8T!-Sp*S6CQiZVtph!@)=||1$2U*8PO|4zo zzDkZWCts*$*>6|WS%X4N3xD7KvT-Ku(|ima7&qW7IDPC+{V*`X&HSJ zI|H<2{9^6^5pt{WpwsXjdDGmzZAXSCDdMJXU!=%Xv0zO^t-U%f-dTA`A~oEEOe|x+ zcNygn3_HZu2AG0Vw%ViI{0&NzRZ8V;W}ESvPC0I=DLL>KE6g1%ERuyTmpem-WPLck zxabc?Nh?-f7e0ba(a>9x`cW(;Nx)JR1%+(qgCyP_H-=0eFrXzSDFai@FBWJVM)uNi z8L&5zyKR}mJ3ra-n})7>r4|mgRzTrUh=mV%RE|{_ge#1ZK~0fK07?(;Wrm!ldqZ2X zv#X3=XFe$5E;C+4N?Gnalp1gL4&Uw{I)t{^S!k+5$A}xoxeKQ(=o7Erjb);ctVAo@ z$aO_#>N=W+*sZrmuMe}kCDys2qns7!mMmDHTVk!IZpli%Zi!`glFreXMTh%u-yIxH zKL*Ib>2Ntbh>#W86j)`lwh8jaRkNj{h11==XU|?7y?Fg~N#m)x#})a{v0_?lpV|*mf~df*!d>hsnDscN>fF-`oc7h{ z32S>^bE`UYf;s%T6IIbx@|ec*bSO`+LdD$`GN-k#R5eI@^zyWWKO%+yN((k~A{AV* z-N^2&MOtnR-_mToJ7aZZUlSmi zm#=GbI~q)0|7qf9I#n`+LW&GUWJ4GiEK^Wj)D7gQjItbB`KXkQ>|o?!!O)EK@TFXV zMTgG17#geQX$drlDc_VZ?^CdCUBRahITfUWqZn}$fmuct@cou6=~}#U>dbC--XvE+V+4RBLyU_%aOV#%dWFKUg?&#wi}OdTEZ>vZ9r z?@rl~xNvYMdhyJbpyH$1_CGro-Da#MgoV+MrPM|Ztn^c?NnwCYLLi(hyS(& zqrG~Kfqf-?3N6JhXM$bMGFP=T+cbBg8Pn_AnK|}WFt*Wwk_vOA$yoFRojJDVJw}KB z;ChsO$Szz$sK%x-5m9L!ce7j(xyUeB6R?CltEcwiEcx^5-AlkfZM)tMs)OszoK1oZ zV%gV3-^!Xu9Z_Ti2F^K$nbEoEcA795!t&+S-Vw;)S8tEJRGI*gB({Z4YL0cq9P4`R zoUT2$ocVQ(jIM2-?#FGbAkK*6I-3*68FNC76R!|r{7@MhO)8-I{lQKIQ`jrBX_SCPCScr8Sr)O2>is`|@Xb{jb@2y5*W z`oOpcT8$on{NM(p1N*uzdnk3@==3IvEU`3!%16&~NRF5^<9QX7YH>esVR@KVSMrfW zGHX(#99ptzMyt?#$tc3510{RQhUU7!C!ZQcCPnsi@SK>YNUc*$NgG>rbzZcPjc^Mq zVPZRBQbRRFOrKQ%olw2w27+&|%0k6!uF57FT})MetpI0$RP+dJvJ02Jm)H}Sz!@zp z?nDzg^aI2QL-U!4`Ubty8G^aq!XK`Uw{&2D2r z$)1Pz=sCDI#}!wA!d@y@v;>5T*U%4#5@k-W2N-~paokFbkKBJ^qvYL}lG{)wsywA8 z-B$kGV(ah@`j@#Cn3Gdv&Z~o|9scviRh@LP+#F3g2zx`qI;B*o|DDO0TS=E3NB)Qn zpO@)jvfK^JT5*-r!Oc3+#^TAe=)>}2SCuCA1i^N9!ACrDE{AjY>u$JX;o!O)_+KpE zj=4JBc)MR+gQrPR0O(T6RF{hDrc-FAztehjCu>rAigG!qdnTNau;_HOlB>g4u)g@7 z1CwcbVQ-~(H92#gDU+=yXCF(^!h-9d$PUzW08A0>Mr6?JsUjv^0;j@=uxp&F9XD717ov1b$e_n6pI1R0-Udhb#p=igTtXnc2pu55YF40QeV z?gL#>>WTc$cPrf3Cof!fCa}IHfko-d6ywOD39__IfZ}H?XAEK+>H=Ep3kxAXoNdkH zX99i?2R6Ix?lqx0J_9(=i5hXogq@?aLU!+NzfMfCQlxj9!olSDxeK~`*8q>>!KQtt zes~vQ<_1Aur1_m4Her(9J#3OK+%u1V6i{6|U+^eMu{iw6%=du%;Vv!sKoh^e5nnLB zhYVwy7k!G6kYs~V~ z@Z8y5syA+UR{tnP2JNUa>)z7mVS>f#*C? zxt)rpz5B!Mj>2#Sf?5=+-wg3`>ruZSonpYns4w({Y3Zu7)l5X%@Cg=n=fpivtZXJV z1$LtUTJc6i^g(jo|AhCSpTnTw1>#tEPKhl#1Y{2UU^G`<|E#wM{d2lnTAmED657#~ z(_;1_Dpm#;0S&XRjl|W|I8I>H3}amjMt*QSuQRJiV#vEhtvvbZ2`IqR{qllos2VYf zhVQTnL24WWU&eZ*S-bKe#5WOs>9@t;LaVE_I#^;4*v?cYN?04Z{Y?vz>h(vFjKNOm z^lytWOeG7qQ1C6>sTw{c!yTQA%#kjs7fLNsHLcGb+o)i5nS5B3U#342R4h&u(*Y}W zf~-F3bAIuhB+Fu?@Ts!&ZRI#k5kG!*jT)fYektZ@V+=y1k5?OT9-N3Tg>-B6o8xmR zN6{4e%J!CFR9_=v=Gk@QR6&-|05b=q-~jKTL_&;(#LAl;;$p2)7X_%CBAGKojqo^& zB$vnYXTd9fP_}PR{R9#))tgPYxH=;^)v$kIOpQv&tt>=8kAgl*~ z$^~BMoKX&nwc8o*MPDNQ_Yd+}c}Ozl=oHpJ5oWudeAUt;w(W{w#4+oQ|IAlZtp`{StDz;yVn4z3Buuo^_2QPk+QRzNK~@3%Vb zYoR@jqHzy|Vl+BM{bz7aIXLjg^H=Ypg9O7-qvs^cyV0BRaktZicAH6Wm_!Xg8=nkM zlU8&r;9<@05t+9VnTX=CNv@Zpqyz5<(WhiEL}j+7+L91KdJYIm+!$dW29%2q6lp;G zI_fq?rfx1pOvgdb=us=Deb6dLrvMvzec9=DqvIqR50mz|D-;SS9sTpg(GRcR9YuSu z-beq$gHW%I-fu(c(J4swDEX8KSZJSh0Q4oESnG|zu4)sAm-~lLe}FoBPhK3nIC_uf z*7q-tUhThq8-4%!FxtcPu}3eSzB|}EjNZIEeDnJ4{&Ez(O%Sn!Amr1%O+yHzZ6%{d zr#qCicn^a<1T4EPunj<)9VE@9^9gWlfXZ-jU3gpxSfkqqwFA2yV#z3a(MI(Rlr_Nq z@#$!Ev9+>tc?tGFZ@kSOhIyiVU_i$zIZx@5c$$2B{_nOJv+}}FAW_R3zcABt;x03d*^9WTw_DDLk*c0LI z+MS!@t1IXTeEo%=b3(hqjbP^}DIRC?zBQ)|ccPlVh(1KL6Rn0z;Bn5KXw6?hoXOjX z*0&XoT(jjTLO~C|+N^A>f0wk|+ZkmgLY1ppGikOTRX0P0U%Wb^a*appmG6#QjZnFR z*RP%nfHhcjn#aL{&tAWKavcq{w3 z`Q2)zv3VRS|K#=S16KUFx%u69o2$X$pyC=CC|cWGKMt@3zxW07cUGgvkE7~l$qQRw z`e{l&$|xxgGpeGsYDUp#``_=qJCM`l@SPkdS#dq1;*-6@eO*)w=h6& z|A8fC(T!5HL>1M%P179`PX>B_;KMET%n&^x>p4oKk zke5Og@q|wph{CCoijA1F-TRK`YB#chL21fv(rC5ZD*$-4UUF%rXaoC2(*X}Kr)l7H zINV2hZdm=a4il#z9(Tx~HMz221UND_-qQ|^&P$L&oqSNNvZON5U^fz14l(3}3Fx3l zufm8)+Q8%FN*qg9mEv@{QnV$$#Pa87Wov%w3`S#E*~Rr+`W&p75$cvJRp`H}1qC35 zu;BD9iL}2P#%)Jql43(a6JS7jMt6J8&`RK!?qJ!5S{5<>2tekI0Gt%^f&}9BDB&M0 z>$YO6PBAKd=7ztm3v36d1Y9SkNe-#7Jz{T00bSQi23f<`Uv!7+tCOehmR4dyebe_x z=XXudUe-NTJ=i;a19ZBF@>OhI5H6cJ>4ADWP;>e%#G_83WjSS()h(q9mQ$7XMa*A@m3yqR=2B&Gq0mS?VyhDWI z#w|%mO1U9mL62V0|D*i2ci;oc@&8meH#cnmPYwPz^Z(q-XXgKz`G02qpDF!6%CnQ} z$5D%!-VC!=E+y@S^&@t&J=<>Zx8&8A71UV1oGPuza+}7c%hP5Opr_Pj%N$S=|9xEV>jmZ|1+2;@U z39tXc-z(#YZe;}Ktp6Le&6>OZSJ!K^_5VITv-N+r{?FF`Y4`s{hP0gh|7JP>U~=_< zOJmXl#F`Fd7(@?&r5oFxXX0dvyG=)Lx=GKikqid7#b_6%hxLm-+n*bPmOzi=RP8#T zKWv;N{8}b@L77M29UPb_XqjBjs)n(XR7ypQ%es+O%6f^YISFO01nAh=Xelz((6H&v zPBj0ot4by7zj1MJyIhp7thA3%Z0GkZFIt?U|ym^{5&#;K4%E?sENsp6T1AENh zL~PXNU-e;Jd;RgrsX%$ur#SL?e||j;aA_x!T*J_FdD8?E+bp}#M`>Hy_Edp)7Z{$~ zAME7Tb{zh`rVaa-y=-q>^!SA6g&P@~L98c8a$T`3ST0sykoRKdwdd`hXmWeq_Ij?d zRG$J(T~R_0RTguS1JGL+bOf)1H)^P)otk~Tf#@s_UBM7m05J2zK?2W`!3DI)c#OWi9N)<^tvX7v8=Hy zhq@(RXm=MgW;~46v^-23mO^+gii@>XO>_5}c!<$sqG*an)~PPu=^Y#Q ziRe-Nh%Lu?#cELO@#E+b6qc=6pWOPZqJDM5oM|!?=ABuLR!bAnd965|7o$xEJD<)> z`is+W#FUXhqYOk}7dejSZLVgxvcoB~BnhsjGgh9}$Gh$v_50EJxM@}$f-!Hccr$my z{eFV>KOH6+k5Hw*?GA9B|G!ps?f=T!>dgMXm(R@ppV|L2`~M5?|GGYQ``BKQ6PDIn z%n^dN5S`>q9|N2Up7#Yi@;GO!EuMpt;Z26wdj9o(ve*B+2?EPq|JSN1|NqA7Z2iBF z&usmlt^c$2|IYXSX&az_E0@0|fWz?s-@iE6j~=#-d%oH259LMcmao);$1mFjPV}zc zCSQmZaaJ_2fJdmM+Mb#DU&$x9{)>bj%gu|6Tep$D{#Q3^>G<#J#?1b|m(OhdpRND1 z^*?X@=PSMxjMjQTuM?)s7l{w(Pv$aUc|be85vFXCE_vKClJ{ZKuH*5z{h_-4(d^;N zR73E*9L;~znlD3fmLv+Eo0L$zm0`Wn#e-f1wJBPVb>eR;-_qsTm{z@s-@g6sTakPH z+lKq*H}z)Eee=t=A{!O8z?z26b^DjNnVW9f2POKueVHun(=?+cD!dp0N_dd18ER_` zdW^pbgBDQiER$dv8+@|_qDJf76c9zi-DY*PE_oppADt^Udzq#SnY zg}RhGE2EvnP~X4mPj|>~-0))f;F9P`9%OKS&RC{>8=AO36yS>W-q?l2iW{KrVfuumzNK z`=i&-UfU5QZYnYlD|>TQvW#^mIRH-#z<8R^9)!P(H}N=0iepxHX;&Y+CwZC0%~mz* zp7j(j)BWlVkxA07LmaHb0NC~FjllKlI2_rRs$2IQG9J)}rzxjpm{&}>-B@5@-Fe(t zwqydP>hRp5Jrb0}Gt9g8_2LL4JqRC6g^zY(;4~|B8^2xSE;4Pu3tdWvt)O;s**7^= zn~iQ)a?(NmPp9MhYxg}G}k&z`M|>ong|Y4O6cOI5;5*L=okIr zuyfo+8v<>N%MS1gbq81wEFqv7?VBKYL?(yRY5M?+i);lC z;ZG)m%VH@G&&*#xaOeN8cD{Bd1CDWKtMVUy{kZK;isRI@_vlHW{~l`*0I!#-p7}EI zz#Mx9Cdi!;hk}5$0?5Y9 zjF)OajGJevD>Qxz<$~PA)vLY6Ua!T`T0Cyly{-h1l?n4`6lff|M)`S z^x9fBnKEzH$bA!&u1UIgS{5bcpSkyG?Z$A>y|Y0eT;q$<;TC6f857s7XLAe|Cq&pOcMXW560!heBu+3uD{O#5gr{%Mi1USMX{c# zi>1mq3+-#B&{S-@SsOA>g`#fL2J)Yw>rgj{58^i6!ufW8{~z`JSI-Q5UAn-1ZFFiC zE8vzN@(w68ij7Ec{cHZ4;lJi5yitxgi;QRbrm!9*-EQ30h?)YAg=fJ$*kxA-vV)gX zbHvmImvlKHX9j$r4&Q&Md=&jEVH$Srhs)Q>g%;-)`7{`4eP-Lq~n6iJL*|I?rUY>ErGPv^tOLUT`#6h0eDM=$vW+WsrM`4Q0tx?WopwXW&j zzWp`w+h6=H@!2WSFa62C|L686Ky%jr>c-l-yZ*1&HfHPpeSBu?|7`uAt^bqw|E-J< zISV!`zP06C)${qQFdz%&|GCv7kZ1p`*D9&|f2uS2e=nbz{GZAHnf#x4|2LHOM;-Vt zWXZX}wzhIEf8%jeR<3+&SBK8}59iC|U^kmKH?$l%4W@JR;5E*%+A+EbVk)x?>5%bu zcw6R1Z$CO$K0dScf42V5*8ki1f74li(pLbbZvYa>D2k>7#1m1iWY`>ZhzHZx zzjt8XT$#v$p*Sb4zr@5bV#@Aau;}kD1A50u(+8o9K#>uQJ+Mlj&R+ci0ZR|ki z9}=CQO-@{gId-E3crq;7pm2W3)3*h?ChLfMpo%pECIeV1Ey+o(1pW?!VYK|v zs9MM9WMk3R1c2a)Vh-Q)ngj?dQ!KDD1JgW2Cn2P$(dc#>-stn3u2H=-7w1miR?_bD zIz`6Ir}C;fyO@J?VxJ*D3}_tQ8yDy2b%=Y$91nry$7+qplDD}PI$}HF9M7PF zS_?DLy|d=Vy^dF0^S&2oEss7l-NY??z2pRB$)}=R!4&6urzLbG>&D8c(-OzFnXWp~ z(oc8X(NZf}c6_e*L9Bg+2q3x$JX|<=gEaGp)8H(~a8F21PFNBmg07j8!9VZx*MdkE zU1iHtl3ZAsjN)HWZzdlbt?Kacv9k>2Ei-6vbiA8jd~r!l(y6oqC*7H2it_w&g(1?t znE9zpn1$>=1U9kK;TvPtT7v52on$lla&y5U9x6jLtf!!4Z4kqRHIh8eVqr&qOAzRg>ip%1Gxk4djU|J*K9LzGx{pOo_oP(;4iaMsWeao7KJ} zzb>0&1WGM(;wgK3yalFc^xZ4scYwK>CVtN2!=Ke!mK*GM%qka14wdP(``R+beKA@5 zrRem#q(du8r9W!Vrpfa*T_=BsByK_cXIJ?B89u@Izot0Y_~q~atF3QtxcC27s?}Nk zw|n`_;{Rsxf3x_%N#g&T`owp!oBllM;LM}*1c-NCAPmqf`pV~dbnv$R_URA%FZb#{ z)lk#FT5Z(Y-yJ8l?Y!cvR6JR0Jld$N9p@HbqvGFH8qG(KTARV*bX^FRtk#m_wbe%( z!IDp3zkKrI)!q>>A(mfnRvOi$wO*in{b2w5qxzF~FAk1gyrRm@R;^lXZ>$!rOqJG} z)mn3-^<9xlhcBN0aHL3FYr;~tx)~<%-r;jy_PbU)*{B|G2ZwL}=QoFVVH_22HILW6 zJ8nG+f~L}%$Vs#LU8}MAC=6ZSL|1=(@T^!9=JGl${-~LJw^li>W){cX?L^Y#QKP!n zu4J-@E?udv)tX5o$)Mxm-g|-cckSa^r4=qpfRQ+YAF7WwR$CRMi#oa@X6)7$=+(l( zZ>h#2nv(8aTD}+$PwU5x=2@)Mzjs;~BZ)shsD$}+8<>oy#fj<^z(=NtIBz1GGq~tP z_EvXj=cLoJ@+6N(eOx1U7$zcfmnw{C$WuX3?txX1oJ>5uatCilNdSB+AGNIgd+V~y z6cMP%$8COoh!2AHH8_@&u`v+1jx=M#qDz>eQI9^TFKUR?Z$3<(!fLoo@f(>MgPC+T zbu|9g;Atxi2ar)GfF>0CI7wT1cAs}d(yf}25uik(G|%vh`&@iC_K3M6FQCffqWbYQ z#d!19;CBe@2XWI-HhRYB520vy$40XNp^GD|8*z}RF{u{C1) zReZ55{KQnGWP#mS%K?j;QXX7Urj*KTm<3nHi0437r6jo%&`Uv22E|82^zY6cWi_Hg z^&`v>>Rw56v5aGs3<*n$OVFa4@H!aF= zX@SO#Ws@`&k8$v(>lghYbT62Nb&e;A(-#w^`%Lk;h*hI5Z3tVG$cI{zAO*}bOmb)G zXHG85HJ$Gc7T8qt?b6;ewi{!p;BQqKQ+Ww%|mmQt;t8K z7!7RiHr;J%;i^sq>1+QA_Kq0G+!pG#9I+<=Qu!38u};A5Bw$<@Um=GQTsN-9wMhz2UNi&RqgkGEBhWG7CB^==1dwrNWeG3%zl zqwsaSbdO|wr0?FfFI5wFMwz^-NBUB!9e%5n$)U?c>``GZ_l}BX{)l@s(W9aDejkgg z`<$^xD)T@N>s$A&DcM5XBSj||YhB)HhO3g;G_n{%^s4|rSnMw1Q1xADe8hExnHh2_ zXN|NT33W$3(cj0oG|ueWdZa%7+GZRhZ(08xxJ96xJCO~gy(@=^Z-`=cCPSc&TXdEy zU`zH!FTz|l+c&Vgwb9-WRS#DsuY#|d5MgdTxtp#k_|;5K4XIIjcv_Jnn1ueO(7LYV z;g=sH%X_pHc;_P}Q<1jQ)dHig6qc`k1n!CY$}{Mtm2Xi@*T!iQoM7Ji_fBlC#>xawb@5`VJK3Vm@uhOGS>SSBN6)pc-HWOjue)*0fze6Dxv0whaspKkcLZ(x0(No zHrQnvLQx>Z(~6|Jh9js;a+)BFSOIcYr?ftz3R>$E1~E0q1EeEQlCQWGkKupvbE>&B z^b;=o#>1U=Er&3^N8KSd8l5*zz@`ha3xUtRo6C$I2XG5;4D?G zG2aufn^l3Q4(} zBgc_AD-T@?;?+e93jvJe%ZDpww1l#qsfF4+_aE1^(@Y=@ATz9v%Lw0RdT8zCz!Zsn zYj41xfw#gd8D_TkintI_iZQgZh1n?6JDAGbpucBXET-75WHj?c+~Dl%F)x!TGI>F{ zsgw_qPu7ZA_|zzLllCY>1ET9?Oc8ffXs6a(uWedIPEixUXax&i#L^c~+pVT}!P;Cd zzQD0G9SA&!KXm)~_ffetrEmq*SHd(kMbf=f8`+byd|d=eWOqzAops+DA1HarN=lps zN7D!lQzEec45Q>m?)A!0@IFAzLJ8hZIS2VHXA();E5iM1qEl4pN#sLg zaVIc=HMK0{>{9-YOYdrM`r9x{xLl_Z%lDhwU|bpn(pf2jah=a1n;oqpDrq&Q1e3DW z;-_kOv67!;dRsq4ugqSu+Ey3YDC>}pRL`_PQ9J4szq8HRJgzt^A%dMgK`o2_?si7W zQj^lz@$XB3;Ca7yi%9V7`0r|UeZ$TFUaPEEX7S(m@iC#To*}nlT<3A09S;X!!FuDO zvwV7SVc%}FMAsq<=8-ofJ4O0E@pjZry=tw9+Itybo^$}@3)^~jYtJpy>9rQJwo)yCD% zv=&io5w$ia!yiOAv`mc6mB#@3F`>}}0R)Ip8BDp*2E_)iegeHG^nTQ@OA8d?;3|Y^ z7Du?Swau@(7L$nGLNvsz;!C^3QF1Y?D~U)Rxc-^#ctiZ3jN9#G@D@Y1vEL&>-f|@W z;5sEqzU?D+tAE+UMGRK5Za0=TRunyCDFCn)!)K-pem*RGjKhOOv^ePW&Ym=yXV5WY zCaRCQ$pUAAnRnvY;4 zNzkq1>rpb~m0xhYRGu-}XH zWMA{xrn~ANT4g5i(e9jpt}zBvjdgzct$O-48QsN@`^s}<0v&9E*_Hge*T8~Cpc8_fcbbNiE|Y@A#THmwTP_IpBh4TZ6;o!J!r+>T8-NBS zfOYzZKIHZl<0CqHnMy0s1!zFohoU&rFY${Rs%Yg=sp5<#eAy zBz{j)Lfcp{w)9O>7t;f>BA8*yoL0`Y{mvLTJO}o@}JIem2cIL z`^`FAA{n6#C__VRgCO9Pl7XLmEW>?oHhR7O$Xbor1c4>E5z!2mGXOib70nN$#T1{U zJ^~@ST)d&NS~mHa4f<;6iPfz6X~XEB#VPtvKsk$O*(95YV7as^ObXF0B10Yph^?3u zHMkci2wSec5HIni^7mjSd#TRmri0hd<7fL%-aRkj?)p6I2A=Yp$A>Xrw*DT?%gmqi zAXMj39?}m{J$lj=`YDQy2-nPL-t8uoBY^l;_9d3JfwAZH`%&L{OGgLIdnTPl*q*1M zdA3r{E2})a%c=*YVWUK(7L}ZXhV^j;f{#xGXdR@f7>(*s?4>YF+K-VrkH(-|?*cO< zmAc?D6iUatUgzqlbDl&Xm!+a{&_C&b{!350qjJOnJx#h@(yn)-^J~mDFes27 zKtx4IbK>cEFi3jM>!w|pQ)Jy74gdvfsNDTr(G0mI)0*`1A6 zuZyK|2dQz?zAYxY}- zKjoF1{A)WW`4_C9hKXZ`x4XZ!kMX}+e(?=?+c zuNS>Y<S2WUCDY9<%rIU?263BXSKU0}RnbONYH7pP+mi8)arv|&}hLgEO7}FSHCO+e^E4n2S4E)$NLL~ zdzd3*fU@eongo)nBPpdo!!8WfRFy+XJc1)I>?@!!b%Dmot@6iNHiV^5<%i#Z^{|5f zEW!9N7!w8HD6I{x3Q&*gzYaw^6GZu_Fr3#!+u<9EK@EiJpk@?!MMNhug$ncs=MA@q z=@=l-OQE|4Ugm}u;pAQ+=RcA!qX;^U(7P1sA(eVNYP}r|lE!%^tnYys-@6D&V{b)$ zabAZ*shHBf)H=4SISReM5(OHDUn7h7-kvv?Omal`C0)<7B=&Tz*PqT;j{D8jvnJ@z z{fnXZ`EccBGC1odZ@ka|hf$|DrUgI!@}iQaBmB2CJZ%h|5r9RzHyn0X&{ZqVo4<8H zD|%Lcws-i?7q6oK{0Dy=ymD^%509Qb$zq3d9n2jv}K9W-D#p~P=1^o%w<~Vj^`|$ZK=r0dX01zHHLqP5EI4(L8 zoz`8DztgW{D2_uT5&0F*??&??;|x(H>7m;ZJC+`;;fYjEszoh>RoPA%Gtq_tO8C--4I{l|G^N@pt^zHt;Pn4k@1yuOnGUjYp%4-b2mN z*$zf)9rrp20R{+=c?iZ6937A)$9nqxv#0+MO}j7*1~1LZR5}GDd&wrBPSHOVvoQ_D zvYe(6%ehq8=QvkLsI;)$s`w$O+b)RHc99XP>E~etK@)hdKER%~|?e(8*|KLAQT^ zE#o2rv!LgETG-&{@tScY66i3Fgn(%4!NwlMmZjuNV_boLr3V7m?x)G@gYwvpf4Z@! z+i5377(Lk0O^F%(WPgm^a#tkwp%9$3i)0-Hx*ct$GV9x6?}?c3a!7= zu03p6%ezOfjNBgM=Te+q3;bu6=Pmo@-R66_wRlHDbS$lA zU0E(mwl(K0cdHb`m~bTkSablj?GetVz&~=sHq&RPMb+9gDPk~4z#uRmf6Rqikf(U` zL3d}KSbOzk+#?da4(MVOiE)q#N=IV{ z07#(FU%+#A(Bgr8t|=BrnPio-zIHHrEl*B4gQq~CaO4lO(NRBB5ex55uhZY0({HV=Hz=4&3CiR2+5rbmw= z!`M2>8veV+)tjSs-8CYfsf8edDjQ89Jhip8+1<1P3tn4!Zz*8F=d&|$0+bbo#eC4U zcoAr{&hPgH#On#Zl*!uR&P0~XL%~s;dpijR3P2x%F_~})Ox}Zeg;@uNka*~lN@Zww z#8UcF4-IBio=iTa5UYbZzEmn!JiRh9^FTb?_h245yYvUcJ++j!#MUw_g1N5R`)`Wos~2=-t>D8&TcC)cAdu zD9-|jWi+zj@J1Ei@7lC#C+?!>xr2Qg!7LQS zN5TD9O2N3sM{0hT!KB4Fzz6rNqgVnLk|8Yyo4i}^pkU>RRSN_s$Xma$hcdt6bg|G7 z=Tw%_AOdhHEGB@UHJjWdrP(>gR+U?N=wBl781aj^&bB>+gbY*PWtfPU^^djYUi>(eZU{Ce^soZNos3x)|N$eqtf3Tnc%;& zbVVo0AaHn^9Tj3oQ0zk=;xUvFQ?atINeh5k(8!WG>r|9#WzdIcmLht(@-e!c@xi_Z%KroKhX~yut2`OFP!D@j$OVysh1$ z>x|$QGb`gFe7l`IPBw)eP3dCwrhMqwd@uX>|A8qLa}XbzAn?X|;#EV%42{K@t9vb})IO=KbH-Rz~E0`Q0qQ_;W+AzM)e=T)|BZ zB;FuaNB#`B!ZC0Z4t#&zY2)p=Nsu9^2T3x#&g^X>FKE=P#6clmAmy=X zU>uryiQ}@DY;mn&mC5^IqO9BWU;z}EYdLy*0^2{xQYc@QzJ}*4##u@%S3w(tdsf89 zRNDyZiBi57`8R12Yi{Kkt^G!H7NKLv9%?uc<)^_a&O(Jhp0uS8jCBUYVOFhg&_x%& z6^nYUg!$*{+y|L#BHfeG3ecG2CJDw1;eR-{rS1&3rN1TMkb^|3ot{NP+aVmy*0&R} z&J?wn@dUxRgT)O6ypwW&!)!3^e*`N%RY zI+K0KyVyt`Y%ZE{Hl5~BKM4emJb{q5$sj4u#=V`SsLDhTVR-X~H)~|3anx8Fl0&`_ zdu*c#akw{`_0h+Ef{3E7Zk1v|A)!DMgjvReTFl8{MKcZ{gJBLM72&NII~x)R&;(B1 zVk{t?iQ{f~wu5Z~2=-1m{8@`L%^-%BBhlzO1hBKpf-qFHHJgjbPLf+0&Sbz0UdGr* zV37AUy_AttTS3#q5%*jj5nJ06YhUi=4c&-e`330YsA|9hL+alZT#+Ia-wHwV+Am0P zmE$+03spN?v5RGM7N>ah@{<+Mz7=P<;Cz&ud6y z{9W)GiSTP?HaP0BJuQXDIwCMq5nRSezq z{@??QD;1#!#6G%K%a8%20z42Xp?U2>0q6(`1XzC$aVi5q$F4LZlqcEt{RiZ^ZGzG| z)F_l(6kli(GuD+@Gypgz;wOsE8qk$%rgFXTMB|hEG@P`ygU)+%{q4Z|Vkzqsio#mg z=SCRz1}OwG1vB4wZD;BqrAUv#s6xuQTngPc740yra6q=Ju!Hy#%pKoD*Ps;;uA%=O z71>p~*&U6?M`Lq{+I_VKkOMJ$Bsyl9bEr|RYW@Daq+LUt?MrT(6*o-%0qt&>FSAv+ zdEDMA^yc@!Rph~Up{-)VQ@B3}2R*g{YKWYQks%bxK$bR?Inv}Bs@~ycOCdA4o!q)} ztHX#6W`KbTU>IaIyS6s1QeAw!YBWvbW8&L|<93pQ2NKhI%FYlsQ2%RoCh?;N><|XL zHMJv%&^?O6vk?gWxhY|2{n_TuBiMmJ1%(!g|BffNfaVL5Gz`&)!OcUSgPlE+grpEk zRtqvrzCe%D4`aphQxS$f=2)K`pv zPBKQo0zCWw?uEI`lr!16W-tp%1pshT85Xdu#qu_!c=IY<{G_*0z>k<5`>+pA@wWTY zr^&1j`RHem1*sUB+d}*kCU#5w-*3MqH`#l!g+3J1a@ymCUm>6aI{GS^RzPkPRw{l+ zZ#5aj0k0m)S0D&uQEGT74i6epJZPyWw|=g0Yn$RJC0U@sjOSAay|K&$tb{&So8JYn{QvdPy`39T@fu5!R<3U{IX}HYkEh7 zJ)RGTqSdY*Qvp~_#2aE*>!N8#$SGQ6#7`e#@3*OUJI2tB&EjXFGqcbf;z+E+VHkxi z90|_R2Y1_F43$@iNpFJ7VU&EBYsm8MHp8i*Rgk~bBpec#-;bu~(cLl~wZ$`-Exxkm zV7J*_IQ1oICOW~;{G!u~&aT1aE_rS;D~5D|V40xTlVN4CJZEhc)y<`JgXttL8CWN=s?af`Qi;Q*gYp@H^;x_23Hrx;&5F-xIKwF%RqI61jtD-8m z?>|^ij7dhXGPRW{Gtf2yzqg_~^xbVshlaPAmf8&F#Nh9?ldqEEJ=1J6TPY2v0iZsQ z>iPuK@P3b)^$QbwS3qHzmNor$3m|)#+-r-Dk6c=bB^n^;EH5d}`OsXFvNdq?DRdH* znqcxN1uqVY#^xfRyzZcWnw+9^gVR%{DfsN&=6h|P>!IlS4GOdJkH2W@(sDqbUIX6$kLR4XWA}DvcPxHBR>G6DGu$E*z%c&8pTIQ=^4> zy^BJD3)CK4?w0eBIGvOni`_vn?u*ZEX$FK19&!18XJ-r##YEvBvCZ%PtybazHRuQp zVejtIA`#chN4@D;i{5mS0N$bd+j7#f1NrE^S~|U$#)S^uNfq>JQRN_Ot-tm=f8E@A zFdUwC{yJ~N@@a=nooY-x#7_82>CGvydbe(}rag2344Ol8Q@>Vzs_6hk;#yi4Q#J{l z)%)uA((*n>)9>7owX7 z_t{&yfwUrz$AL#Y;wwoi9TzF>2ltrS?e=Ye=3(M<7ij)#L|%a{%p{dxZAk?lRWSPp_qeUz#-bAp zuq&G>uL8zd9z9~v!MRAuK^Y@SZ}C&LN;V!P_Y8CuW)wA$a5#h<+iDr5wEZjI3^H^@@NfuAzP0@|o=PC8^^Uq_HBmKKQ$P()h_nJaIfjC^wi`%o zh!9hOeN}sMWP4!xG$3eTO;l?8c|+DUSLqBdI35bX`Ikb1G$qc?Z?dk)=-eKEnhrvFTztv-xM8L!mUSEl1y4qyV@2;pdH|VpgOMVe3sEnGLgHN0FLRayWI7VH3 z*(74gi2X^*riF`OtcZ>W4SKymff3LnB)hZCl#T@wOdyA6<0?C)PQef&TQKXT?5TD> zjs4SX7=zcW>Mq5@J>`&RNZ+HI5v_sH^)kP3Y-?d2B9r{W2N-v#t%kb^zv9Q+f4X;7 z7=}&&jbwo1H?;zl_~#B@^DC6d_G|wS?ZUTy9^Z;)|2)ZuQ)_!bouzEtHx~~c+>(W1 zbZJpy;FV66q&_cqejYRL-!-t-|6F}%C-SqKQ0DLr>51`kbtu3qdGn5y_lw6R+8u#| z8I6U}^yJY8pU5a^Csl&|F}NC|lgmTp!?gEv^+E_>P&7@&5%d$8Q<(ZOO=%doJu4~` zCgzNQG)(gY@*7hfOZ=1qwSY$)Wo4eorq<_zMXC$lhj7EYm%O8Lp&LaXs$lKCCwNPY z{2EQl3MVNTz#ocFOY$}{fZ~#bC&Y(sQEctFsM?^o{5RBrC}Pz|K&BJ&xRjUrli*B}x)xh9EiMqlw(^acYl%jsmS z;uLK_Jens^1iUyWz>|Sh&sSChw81t=Ff#~5#UogeVQH6J0A3a(d^{gZVzuk=0=rBi zhV87_mZ}9Pu-`mnoaBNHI`GJu6O)Aof?30%wqQA_z1!EflTYIz@-BQ~f7PFlri(rU z9t!RFQUtmZ01$rTJw>Rrwp$!|LB9;b6-TIMnP3kNH9nL~ftU$4*%;!;IM!q=xFrZMFW$kJ?_&d~U%{RVl!t8$8v&NB+#!DSA}Y%pfg0E_0hz0A4W~2{^?%4$qQo zP?5RpC?7yoSd36N3}Ni-Cn2q3;XmB&@5IIjBm-O6aQRF%*>E?sO;1=x5DTt~brt_Z z4XLPfsaYGv5GQUuDg^EIFfyIy-BJPcAU#pUyO)8WooE~&D}yqz;}FFjoynvo<`5Nl zhtp+)%!=?Qv_LUyBBn8)3Q>z7IXX+&g&LhnBw>jUI`k{j85mahsKkg|NQPA{7`R^= z!@&JemIp@lyfQ>p-e*4irfr&Nh$xq!I=uK&dZjU!jm(1t{mH@%9!E%&h5k4IjV>^P& zB8H&>jkf0w8E`>nY=NAF`6YG2EkDU)oVxm&!uFicJ3Qf3v~0#s=rUPe@gp|$kP_Vs z#*~rs(FHJi6l-#b7_zkP9^q<|I^ePpo3#+wW!Kkyju!`w_9f|- z8ms_*b{FirMf-?zFz|SYP0F7YUkT`5)=ed=i^_QfmVP~64M&y}wOEX0D_D#J<)X)tXwT>GA-~UBhcLHLQQOy6x)+?|hX+#GV(CyFX&5_vfz};>@kMtEns!%}R zs(+d6l-!O^y`6kT)mP$YoisUx8I^JCB!4)UQlyWz$2NzP$%pw=o<`EMTZjwPJPye` zq#8GaM3x0<1j)TlqB1nbAQ?t9$S4>Qb{rgkyOwy-eiT>2-3$C$rVVDGHLRR$xiHu{ zU%*Nvq{}rWZ%(GlFX7G|S>n-@RE~wcS;K-o%AJ9^KX=u6){ESU(Y(X+F8BBI~9!nL6vz}(f>>+m^+mrcHU>Wm1xE?%| z4m?%S`zAYnHGo#-w?}(IX=mrv6d7VNp??8t z`D+&~+G%grySohmI%;L!9Q-pqcy{>q#haFZqf^_vEME>y7-)hU9{pJ4pY(e-T}(&8 zK&!|`ob|x9zPGUltBsKW$h=ufpIHxsc--hc-=pZkgTHmep3IInCW8%d>@4Bl8M9eb zf(XE(+saQf$Wx0~H!xZP?Q~Y3_L_F~;2?^29+2WQLFryj2Q1AF1i?@MA6SKPMOW>* zBsOsiS4hcYj{eW3Qw-Gomg#%A;uTBg$BI5b50})A)*gqE$c^9^oe@bVW%~n4nl(!VZ|($C4ISU`~5vn z;nu#Fmt6wx35_Z9(Kg-+wV8tTvRa!D1d&Gl>pgC>E14)67FKzSnG~){!jw0km@W{X z0rqsZKN3IDp$r^U1adH$nFST*!&78w=cFZ1wCrOZJ#z7e8r5kk(8B}g_$!wLs&W>I3zIeWQvY54|_=WHm^b385b3ORi({%oyf zT~6hOyC>2EYPAqJ-*)nqld_EFh^Av$->Wa3UNISFh;p49G($S!{OH~t({&$b{=Hpl z1b=+_F^A=UXordHktZU`Pcnk^rXQwYe?y-bD!=K+m0*hop?5TRcRDXmQVeu6t0TLx zj>A7s;y+K~K;OUDlNfa0`B?dq(^+e_ChHtu$-TgnfEq91wFL+C4aNm7c1|-0W9TPH zt^7swsJ-~49?dI^R$Ula;_NBU5#QDN*9b zn+ge44yw+XX;MO903ckF$!s+Akh+&s%TEP@dUTVUk}s}zs?~skKHun(i>}v&awV60 zQjSk=v|rz!Cw$<9e>KkE7*f5gGd^^_fY8J>UF}<3}Gp&HhJn^cxH%%Q1GgH_E-1#GA{HWeTrO1CC1t zhAAKxI4A1ZoJ@$9a%N0i*Q#w2VbU(^4KeJiXTX+^RwFk2`(VHjO!oyCFsHB!vtMqs za^&Sb;;SWZj`csdfUlXCxMV;CaR$ zba6-+(SOBYG6Tk%QM@g;Ke6X+|0}@&cLZ5}L}$u?c-4-u{o)+7TCwvn@ueY?CEpu-zDmOBk=2ti};S?Y>I zAst(00+R&CCU0=qP`n1wJ0Vhoa!J_;KANi65_iYB*lkrRDNL-Q*iV>(588GT4TNT4 zfs}m))VA)RhaKpzB)IU*B!%Mha0MIkqsDECy&ImMDy0*v#zoqA;t%;nj{C#V{N?OH z=78GbiUkAx)igg8hms%;^;Lq&=$!UX=d)Qp?wviI42M$EJ<5jJxThOpw$0(u&dz*1 zh07iEXwwMo01W6yifwx3ETwiW@f_3N2?#ngG$q`n-n+6DzUaz_mh|BgkZhxUepE-C zt9eMY3STWGP1Fn40v$Pt>*^?fsbyPk(HbrpsXf=WWYIfqs^mu>c^5F63;4J4m$2}d z6*oIJHSKIJg69;-s;Owy`idrGc)Vau;#lpS2)fUX&GdSZ6Dqi3;zN)D=`5I!q1M?> zl#W4yh88N9Rcky+blxO%zk-r#y4+hkM2{}w8UrVkv0ug8C~)-tQedLRr0i`B!(Ew< zvP(M691^~_wlKHpR+~cp6|jJ%|Fe~(I|h_T37?n0iF8Z0e{@5F#U*+MTZdXJS>JNi zMh9Se&Xd;3I*e-%r6>6YyII~_GaHhkY^;>U;0zCFg&Yq!E<3}ARZlT+aC;E!$X6?^F@PUz&R&KtZX8B0ZA(+vy5fgNUM+}f+9CSnEoRUMpRrA zRuzhifd{|w-!~#Au1-fx-_Xo*mE(1%iM&O@x;Vzo0qrpMk;jUv2EDnXQxduj$cy4T z5E5DXOEcvyDRts@w|&ez)`;jXYfXA*af^TvcctJR$DZ{$Sql^UQ&W%qB_CE{8*wi3X&zhJBNf#&P!eb8#bp(JsUr+Uzj78 zyBQ_F3n5_%8tP}(vC=4ygx zd1cXBHa?RiR=9p#OAQVx?Q;{*gz4)j&^S}*9Gx|w&6}a%9dc>MO7Yb zE{hei<}sxOn^R7G;*c02I+H3Wp5S|~XS8%cGxbTOS6gAqmDy!VmCv7Ur+1}(qH2@& zX1%QktTq5OIETDjGFM6Rn@k0uOFts`dR6gytsDvURt(-ULqcmBG-Lsm_jypi2&i** zJRjxbs@zd_V;o~+4{ohmlTscv%6eNG+bzIjD#{&;BV<^NkZb^--(}?s__GAe4XQKv zLXg`lg5t&G_!yFj(qHKi|7`WDQ#$HWdft{Fkw!EDh9s{LKjJsu2STb@xBC<#j;s%i zomr3p%%3&fm^A{n?zhjrdHbDIfiUHynB9**tf|j`9Fg4farC)|DK0Fzq4zwVpVYhCh~*x3>EDku(TCf?wgA+}jMr(~DHb1{D{mASCc-qEPy#Opa4+69+x+uV*1z8VL$w2-s<|^Q6 zwFB!4(2{rrIy@o_J|*5mfzqlcwa-o0H<^veVfCSY@$`*!Z1lewx;n@*5l+j1Da7Xc zim8bi%WO+xaW&s-$_W$*OS6ISCH5j`+*$rF%PTtIryJA@7iebq<9=y5i(Q-huez)9 z+@^f3&~vM_@41?*iQaArtBlgl?>SoP3aLQldW9m?PC-9{(BIfTi3o0%^b1%3$e|w{ zQmO%v)h9!jV(Isk_Y==TgqEOxr9RBT`Yu=J6zw1ZGIo9HR zt)<1l{1>i%2pzVK9rO?_x-hD9b35RXd*E1Ad0rHA>akw9nKA5>6}B<5j`>!oxx&JX zA&-)SfL{{{p6=zLr6s>^G%+$5=zZ~ep|&2Hj+bhk*jP~SqUxCFaVqEc+M6Fl2C^k0 zUnE4+tpApTGEG}4I1Qpeq)#D~? zsZ&r!9GV@$!X|jLaR-Id}-o$ zEAU&-Hso5SP6dVnd$0z`a6WLS>6n-rOcL`K1^YC6(uUNK7Z^jL4lcn(L^^RJ5peZ( z)J;;6frvY$`_vkEbcRorJG2U^0}P z2=nZVg>uzh3hfVeCeIM%ST+ zx6~rB9%Lv5Ep)I}mQs&=x^N50Z8_Z922_(;3nK-#iwR-QdO>@Uqc35(r~tZAc^r^jYzTf72iYPh^kGN0 zu~z}qjb>JMJeq>rRjGS?e2^FhLgwo?yej118gIW^Uq9Q7%fxlh+mAW=h1~pVJp6+G zeI_Z9w1{H{Sq-aza$P8s9ZN`+PX4`e7AtCj=KF}MriEKMXEZ=o=?~?xY_&hGx=P>& z`7e`KHOx^!j4Te{o|60({z*-KD1|(lP$ECyvjjT38YzAFsaGep2aA13oT($Z9&LMx zpxIDnCGj{wh;lM2-IpdpXCk~huC+j7eXw@(%gK+US5$#p40O&f0BovzIvI^7W3dkV zWXq!4gI?K=UJ_Vepq7>vV@$;d=CB>jhikr(H$Tp&XiihSk2E23X(K=)dz+WBjT;6n z8Ysp`fV#v@qQ-(V{L~yK5J0ZQv;TavvHx=8hr{pIEZE3#XWc5Ytv^cMyxK|FIQRwM zYZEK<0quxFJ*nEkI2jv07OG&K6PhU0izX{4_`=Fd$G^SowG(|`*5bW-`zF46Tfx

    strPr^V^;TOxHR_8uJH}<2Eb4u2YkK=;|A%LR_gS@jF)DyFV-*VE-(CLBy~v{P zzxToM6NY@n>oP6e{nEBi#mbKY7VNp5n6{(U~p5WAEGx;xZMgZ!P6rqq#2 zg}av`sN}~dFW$KHz4l_Mg%|dZ$*m4tJJ)_5uQBth*{blfRA^wG!N8sN;wVAh zc*$VFbI+Q=K+}FmIDnb>&9FzFeJ2cmEWDZ$uN2 zZ+qj4zcx<;_y5w56XasG&%3j&E;1P8ngy*Fd;HYDYWw73`QeGLjDr>;~kZf z&yfcRmQJz_1y91Ug+AHxaT2u?IH}5P;pvm{SyylgB5*{58tX7=$U((S zu4zT|fcNwiINoRZaRJ3@>B?WGwxYEYOg|gskJ$;bPNKl0MNGMi*(mh!2OkL@lz%jV z#e2rPN6icx6q9*r?R>Da52dqGpqqy}J~`OJl1elxeUt-`i>9PTJvn%} z|MEM>VPgm~q9ut{CmDGm6ti62+_IQl8z18dt6*+*)55aKaE~&~s}SFaWvLI;k&1W) zDW$=eNG+jNAT4d|x|0Nx_x;Xu9PvzG{kwZDJ!4g>=<@T{!Rq3Q*h!8WqPSu1I;(J) zoj6I>>ZGEDmzC14UPEc%&|_DM4?FOHJ|ox1arM?bq+<5~7sw9(drRehsnBFS&%1*EBe^ket*v*6VEUa&dw*HHZer$y=8|^gl2{`Df2|y2HbrPhVh#u=^)|2`6{7moxi_C@23=OKZWEfbRo){KY zXuxdxh&Zt}FqvrhmS###bzne>s`|O!2%0PH0qh2I)v7QBMTbBrV zG9I4!{g&E`mNFAl<>>hgCv(l&hp#B75Xp*CzBUk}8l{#58Gc*^(YBl{5)?(2 zN~L=(MP+O(USCxiKJH2a$SP%JG%H$k!Uyx+HaY{XFTwe&;la(=WH`-0vxESq3a5XP z255RgB!m|S0o}W9@xj9s2MrBqCA?ClOs$n)=w^>Vh~*yVt;=w(k8SmujaK7n-$cqV zqC*5j%loh4X8K+T1bKPY{%d+@9P=r{E|3T@B?D$*mQPgvuE59$B90y~y2^!;UTJcX zh&oYNL3uBLzMsc6+=T9_6l53|hLJC*OIT%yaT*{Dj#=SyCJvG=11VFP9wS}&2hlNT zYa`zF`_Dl@fn&*Bhm-&QAabGYng2x7jlF6zH4My77;96R7EP7>tUdd^UL0lq|FVY0 z^MDJk4r^46(Fy=XrDfA@m-PfpTfGWo^$Mi!Z8jgz7SXbYrs=f$yfo~k`Th$yA`WwKO-dJ2uE>BWm`5ow=t12zxYzPpXZ zt)U(@$N;B-;<0uqjw(MUQIK&lT|fwSimG6|=IQHR8Lm@)T3&;Q8Wp;+()|Sl?}*4v z@k}^tK|Rwm!7I#CYk67uCvBeIg{t?M!wr|#l|dd~Y5@*n=C2W+B}|y~v)O58%XHHT zAR3xh+@c?3({B5nD?o)1Q?CdQ%g=YQ!8TCGE3zp|Pw?|q(~H$0S;8{QOCB~Yq04_R zuPE4cXk4@+*Q{>wjeT9(mUT8>Vm*>Tt*vlH5(R*I>CoDegW1Km>Xo^Av0(Wqe>Te% zQr7nd$11H{y(rR&i6JqKGR9rjcAKB9UhFsq$oKL^H%uUkL+LF~d4k=LB@u&LFvfVP z2>-fyH%}};b6`>atH<_hec6f{HsL&)bXtgd? zqcAe<(HKO5j*V9G`@!NcV;ccZ__q~bOpMQ@GXS+w){tb99-=I4>;qN%4^wxQw1*EI(|0<(5SmVnaxH-UJ11 z+UavX9gueL*z%IX$_78x<%E46$_Pu-{AsyqLcngk?zx=qPZybPjiC)Qq1s%jZ``wV z3hgj#l!FK`S9`YLcEtp)iA*FL$;cg{*o8(hO|$D#*)dqx{$qu}BtMhrM;Qi~m_w5) z@NpY*G8^n7G#E+%$+H;E^JBYJICdHQAmk><0cgQX$HL&-F>3M-nehtbMSc+>9vY-) z`?)yhX1`L#X;{`E6%i4zwb-?VLPkRBj#~-Kkf})p4a96Zwzb8^j9Lk}Xv=yh_G-La z7bCnU5^!TY3AUBV;m^gr+{F#V){v~M8igY1*Ow2a4;?37sCq1BzHYo`LG#UquXF8- z*$Wp&k&sl`pL`m_N~%OjF*(aJEM37xEKXqQ3)oAmp4YrmsgRVywMt_mU4S;^X)m1x zqT+q{AbqH#7Nlu%IZ4oLty%_jA*Zx&vntzbxiY0!z;96rztyZ1NJ%RoC4huRb^dg| zs1KBaw9YoM>&?#WN$o>y(?ja(tY+=k><*<0nvxD`>7P-YDi0EtR7DxuW#%=(5b8D1 zPNHE)?hzLN{VDA_ja|~jm9hR>)j6*thwg-K*S%VTeALAiX2bOan{r}ObAKvh4UL&qY1dxobdnLKJ&8K#3kJr{TaFPvnc!1(Sn%f~o zs50ZKEWAM06xUCah<=#;dUjBbejQxQ1h<@()&J`Ku^JiO zh`HDWj{I5$%|W^XyyKq6>Qsve32~X`BGLnihhI{BSW$3@DpNth;eV^hAf^95MTV;q z8JaRfT8JxRiB~5qkQXxne=(5(9m)@7iNEWR8_0v?Pr2cDAUFKsHpyxP6qOjFc{60^ z3w-kHuh?WEgau|@LK3=ujdV?;kt}C)%vVg zOJq5M6nYVBuSLTFuh~^CylUkZn0S|WxoU9BMq@9D2+st((EPiK>9_W7EwJ=WEx-${ zzhCNltQaa|~5#i_gGAQ(5fsX zy%T>m3l9PTeaA)Pve|ct}?{Xf1N$OVon+-BFo?;Eq1#6KAj<=#OR z_O$TLgb}&iugvGl>bAc0aiPA1?wt#)tPY|23%DST1GFc|o-><4+=o%JC~5gZ+n5yx zve*tAs;5$$cN=mn?m7o6;C$3eb-rC(Ff47GmeV1XtM2+9-^ z+JGKZp@vJtMSQ+ZELHZUmK@Kf&|sPXyG}E`Qpv5Tbc4(aK(8Ptzzw|@C^Pn0RX(uX zj1@q~!^u%L6uj+`&QqcvQJ?6eI~hMRW6CG=8qzCJuo7!w9^PO(lPGtT&yI7}mObUo zkiflW_>}iaxum?-{IQfcGAQ%mjBOsWMs8o`As<+#I-gL|O7iCroO#B-goTT?j zHAM53`M<^!rw98beIO_d43p`o=Y8V7(tF8S88`DrX$UR>-LIGjH_J zYqe42NERK&FDC4SAx^Ro7$%xUm!NH!(!wizZNVdfVbHUnN4d`(v?xqz!Q7JJewH+t#39@w;>XeBPV3xB3jc1F3>9JnqB`)~ z%8KVL10*JuF&_zBVp2>$mfkgtJhE;+EOp$eICfcpUlHVL5fF$ak{6Vd`OMB-5SYfI z6a|Sc6CRS>0WLOS$cR);mVvR48Dlb5?wiuiPA(NpWfqm|b(xuYaK9nvZe||kvHS~C z^T2Ag7qqD+4RZHf;su-HG>x*DgLU+B?%15v4J&OjA4?CVUlhv?AKNCYT1g!%;L2t+ znK8vif5($_8s&qz*hvyd{)uR=zq^(TxD-RZbZ$y7DEOLymO`^TtjsLXUNcg0I#}L< zJq60jhMYw(*9*cLGh|b>ufa;9G&5U!qw2C>1D9T-g7g53dks7(ntRKL5h?rK&JKe_ z8gnUAG&A;ITw7=|MSn|1r${6dRu%wEe7~`WBn!@qz>LGNathb^W@eS21)g>3-ppck zXJ{^E4->u_kTI+dq7xJdfQ%9}re9YMq|t@T;7`qD$T3oF2!uO#k~goueYFE){Q?00 zl6(@XXa?kt)BBL0B{H6}I?2akBhNl0zf_Z7l2|ji*_uyb7MN=3!+7#(EHh^a@PLJ4 zkwE7=1OU1P5hDMD1~tktNtn^O=!Nj&B>V`Axg>$mIpp^7I9Xex6zh@=={F3AJ62lv zG9>@XeqAxBLtnDF1;18con*`)C18_}>5-+TKz{xCxStQerqEW2FR@1`mgm|dgHdM2Fgr0XrFYSqmKQtHa zdnm^}g@H>Unw*KAM$Ev&bjIYj-!#Bj_<-!{d)WO(a`yq-H}U1S>KaJS0_@>9ALld3 z=$mAf#WUGZ@(`~PdPNI@Ch~Ea_a@`M;4;S(l|Ut~ilf{EhZ+2m&5nB==yvuM{QmLX zdz$Ovvp4CF&knwMb-4fLpXrNdKR$cW5(m}Mq%5kl6nTfT7D3WhS=TomWW^A~Kd5+; z4bv0B;f6W#^c$9}_yqoW^=YiDnCwBmT-oN;6l;#WhKuZ3f)=f5mqsajvjX3?*5J$J zg*ZZ!r+8?iF#YD$%LETmL=*Q7^Sv$#xQ?Xgr(Ee4X^3Qkc?_0Wp zroc#Y^loc&``+gJUA_2+C<}ixFNRW>Oh6P%}te&r9496O#T7Q zd&=m21i=M88C}rr@zalX)M-(*wkDp$4QmMdvF(3g2 zo~)nH+eE*G>0|dO0}o8{oTRc)`8z&il&sH3Zbj=6;_3Ea1cyCZ-HO|!5;`bXtuEwv00xr9aj z2!Lwt0`Q9d6a63==0d&qz}60J32RChuHv+kX|plSW(%4UWFfw0{(kx7hi9$lPu@Iv z(N1ogUhP>KKB!ZMn%9G7*_wQ>_L=}LjqJOGT z1R8|Y;pu4Qn7Gb~_)AO#B90?6a!bfk;rUKUQv+?oUX{{ml z9pwuY9YNoJ5n}b5Z_{s|9Q?HZ5@c%e$BX@!Z~wF2mJ685TT0oA{s@RmsGPBT0UZqD z^W!f9zr~=g^|`Trb@MTKaM%BhYJ` znXp-ZKHYA~8RF$2+=Yl%1E_m4z={{@`nN&ThSIMjiW_wGjm&;BO?%T#U-LMW%vMP6 z>bKVC?Q?3UA9ZK*u{a@93>-YIT4G6)&xtxcWmobFBeTje?zPsyY%>OK*xpT=bv%W~ zEz-q63u_y~mHWNEgC&@d_*~-jv^&d(c~<6}uUO+q>`CNrg7)|yEB;iI@vu1BC}+Jp zAUAA~p_TvMJz2GH^&_;d2lwtJ@bA|T?&H5geWQQHZ};zSZ6{lI?|;2{5B~Qc+1%dT zzPt4w$>v1|Zt^n+6RH4Z3YpAn+KFa^LCt%bOrrn&gZ$k2Dj~t_q$nv@viKLQ-eBpp zwf00_^Y#S2c8RGt4WNrzo{NTq>Qgq$cayWpJn3OMaiJ>;9sOu7xLr|!h4s#aJPw6? zQVh=EA(*cyxxHA5Q3(*hAK$%vn|z1nnql&qj{O&c5sypC+nkjo43sBe%09zSo&ywz z5{l&cMD&a|zq?6ZU=2&<7rBjH$bn?9odg}&Dgb_#(9zNs5TBvtSAQEtfte|I$YReY z;t+wl>J?1$Q!yNZN-;0F41?b5X%!nlt z2XSwR)EIw|pY-tt0CW|szKipN4Kte@&$1EC0b0HiNB8033-RgEESsHm6OArebTvO) zfEgg2Oc08!sz9kU-~p#t1W3?PUzTPSBsNxKcL8^>|KtY4bP#1*!6=}{o)}iJadrm9 z=RoklHu^On0yl)(IuZogZ70!m4Bf!Cqr3HCag1hGP%)G@hrYxvsWv-=gu3aWCUcA2X)twuEna;A~QI<@`yC|d48Q&5AzflS0pme^K_V7FE7yI?c(H-!@FTJM% zS-lVLIA}q?ga36#>E9s;5s5f$XmDeWK5OK&F%Z&9ZN38$K zXA?{pLcS)yl4rK8ryU3qGUc`d@A0LMF{KN>)b7#oUSVHgQb_9?d_pP-LmsXs^d-n! z5E)*6e1(C8>9m@O9^@aOR;VFK52N($sn)WLF^(C^%*5&J`G+`_K~4J{Km-l4ux2`MU^r`Qv_LY&Fl-5YwVQ@0PBw%tXt?mq`KGe zDh{QKKKdq7+&=P{vRBuPu?ot=^$~r>Npc6U_)%V+O#0Whz#KptI@MIHkDXHNJPy~@ zt>u+3_(ZE}z)!bFce!v^`wls9$1x`eW(7QUiq9LpiEgliigOP`KBE4?j( z#ZJkEFnpObxshosiogvq(u*aI^4H^H0l>yoa4DHf?Cvfc32h;JB2;74L^3S+SW5#- z^3OU^IiOc9B+^BoF3&m^*F<)|VB=o{Qk2FR-SMbSFqp~<2oTO{)GIocUQL^RJ_e@? ztRyOAKo?}aiayA-MiKJu^_PzK08#Hv;Qbw<#bJ8>QpOKmzw4lxWRb=im}H0_t_T_I zNj`DNb40-bi{Ro^Aq_QqwCa(49Kz?y;nx8STwVa)EN8+)f0B|G09MMD!|TCy+fp~B z4_(`}55trNNn;?v46a&=kzk^?l3O-bph;Ryc$e#7aw8vk?>n>^d?=>nwATs_iI!Ek z%4|vF0J_YS)2xTr0O;IH)-q#hoD9b;_hFgmALs>pRLNi`*Bl#a!vPadKxt>D5J08! zC~=1-Xn5)IMr>HL{u!(ESF{$s zVbS|seDg7%RVfKE*7RYGxrDP0F;~$J>b`IAIoXzL#=pD0aQx`^4L&DDvFKYp7$hQ zBS#(GFUX*1kFPZxEV#q)LNvwjKjuD&OJ!@!>#RU=dSfr)_dM3+<({S#h%-2NcKG(ioAmX;v*-K&343XflC}%q1O8-% z6g40#DI_oy=+@%!tJs!(OIztQ8`ga-Y+YIFJsW1T5x&4L z1S)6wFgtBo?d>sTP=rSbXxfv*v0GllB-l-EcRDXmQoM}~*U<>=7oQm*^n%F5*RxsC zSLrmcxDcNJtXVM@;%`~;Rl}jvXAmCvwY3Zw2Ct?7xof;DZSjy#N2XYN1XrG+?l-OO zmqEH-Y0O4BpSrWvxTx}MmO_bNA0Kz_Bw|bb@N7praS4$V9H>4OWAQ~P8-={PpOP?( znWkFpjlHs(Oj{0Upt;O&e>15%luE{>7<@|m`?b(+iZb^vf~WMt$kF5CHm;moPDB1u3 diff --git a/submodules/ton/tonlib-src/LGPLv2 b/submodules/ton/tonlib-src/LGPLv2 index d93ab1b9a3..ab2bc125c4 100644 --- a/submodules/ton/tonlib-src/LGPLv2 +++ b/submodules/ton/tonlib-src/LGPLv2 @@ -14,5 +14,5 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ diff --git a/submodules/ton/tonlib-src/README b/submodules/ton/tonlib-src/README index 7379d91e51..a47456e22b 100644 --- a/submodules/ton/tonlib-src/README +++ b/submodules/ton/tonlib-src/README @@ -8,18 +8,19 @@ The software is likely to compile and work properly on most Linux systems. It sh BASIC COMPILATION AND INSTALLATION INSTRUCTIONS -1) Download and unpack the newest version of this archive, available at +1) Download the newest version of the TON blockchain sources, available at GitHub repository https://github.com/ton-blockchain/ton/ : -https://test.ton.org/download +git clone https://github.com/ton-blockchain/ton.git +git submodule update The TON Blockchain Test Network is updated quite often, so we cannot guarantee that older versions of the Lite Client will always work. Backward compatibility is not enforced at this development stage. 2) Install the newest versions of make, cmake (version 3.0.2 or later), OpenSSL (including C header files), and g++ or clang (or another C++14-compatible compiler as appropriate for your operating system). We strongly recommend installing OpenSSL version 1.1.1 or later for better performance, especially if you intend to run a Full Node or a Validator as well. -3) Suppose that you have unpacked this archive to directory ~/lite-client, where ~ is your home directory, and that you have created an empty directory ~/liteclient-build. Then run the following in a terminal on a Linux system: +3) Suppose that you have fetched the source tree to directory ~/ton, where ~ is your home directory, and that you have created an empty directory ~/liteclient-build. Then run the following in a terminal on a Linux system: cd ~/liteclient-build -cmake ~/lite-client +cmake ~/ton cmake --build . --target lite-client You might also build some extra utilities useful for smart-contract development: diff --git a/submodules/ton/tonlib-src/adnl/adnl-node-id.hpp b/submodules/ton/tonlib-src/adnl/adnl-node-id.hpp index 84f425f8a2..2d3ade1644 100644 --- a/submodules/ton/tonlib-src/adnl/adnl-node-id.hpp +++ b/submodules/ton/tonlib-src/adnl/adnl-node-id.hpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once @@ -75,6 +75,10 @@ class AdnlNodeIdShort { return hash_.is_zero(); } + static td::Result parse(td::Slice key); + + std::string serialize(); + private: PublicKeyHash hash_; }; diff --git a/submodules/ton/tonlib-src/common/int-to-string.hpp b/submodules/ton/tonlib-src/common/int-to-string.hpp index 414342cd0f..88aecc6549 100644 --- a/submodules/ton/tonlib-src/common/int-to-string.hpp +++ b/submodules/ton/tonlib-src/common/int-to-string.hpp @@ -1,3 +1,21 @@ +/* + This file is part of TON Blockchain Library. + + TON Blockchain Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + TON Blockchain Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with TON Blockchain Library. If not, see . + + Copyright 2017-2020 Telegram Systems LLP +*/ #pragma once #include "td/utils/int_types.h" diff --git a/submodules/ton/tonlib-src/crypto/CMakeLists.txt b/submodules/ton/tonlib-src/crypto/CMakeLists.txt index 10977b44b3..37f427cae2 100644 --- a/submodules/ton/tonlib-src/crypto/CMakeLists.txt +++ b/submodules/ton/tonlib-src/crypto/CMakeLists.txt @@ -23,6 +23,7 @@ set(TON_CRYPTO_SOURCE vm/atom.cpp vm/continuation.cpp vm/dict.cpp + vm/memo.cpp vm/dispatch.cpp vm/opctable.cpp vm/cp0.cpp @@ -35,6 +36,8 @@ set(TON_CRYPTO_SOURCE vm/debugops.cpp vm/tonops.cpp vm/boc.cpp + vm/utils.cpp + vm/vm.cpp tl/tlblib.cpp Ed25519.h @@ -74,12 +77,15 @@ set(TON_CRYPTO_SOURCE vm/excno.hpp vm/fmt.hpp vm/log.h + vm/memo.h vm/opctable.h vm/stack.hpp vm/stackops.h vm/tupleops.h vm/tonops.h vm/vmstate.h + vm/utils.h + vm/vm.h vm/cells.h vm/cellslice.h @@ -201,6 +207,9 @@ set(BLOCK_SOURCE set(SMC_ENVELOPE_SOURCE smc-envelope/GenericAccount.cpp + smc-envelope/HighloadWallet.cpp + smc-envelope/HighloadWalletV2.cpp + smc-envelope/ManualDns.cpp smc-envelope/MultisigWallet.cpp smc-envelope/SmartContract.cpp smc-envelope/SmartContractCode.cpp @@ -210,12 +219,16 @@ set(SMC_ENVELOPE_SOURCE smc-envelope/WalletV3.cpp smc-envelope/GenericAccount.h + smc-envelope/HighloadWallet.h + smc-envelope/HighloadWalletV2.h + smc-envelope/ManualDns.h smc-envelope/MultisigWallet.h smc-envelope/SmartContract.h smc-envelope/SmartContractCode.h smc-envelope/TestGiver.h smc-envelope/TestWallet.h smc-envelope/Wallet.h + smc-envelope/WalletInterface.h smc-envelope/WalletV3.h ) @@ -343,7 +356,7 @@ if (NOT CMAKE_CROSSCOMPILING) WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMAND fift -Ifift/lib:smartcont -s asm-to-cpp.fif ${ARG_DEST_FIF} ${ARG_DEST_CPP} ${ARG_NAME} MAIN_DEPENDENCY ${ARG_SOURCE} - DEPENDS fift ${ARG_DEST_FIF} smartcont/asm-to-cpp.fif + DEPENDS fift ${ARG_DEST_FIF} smartcont/asm-to-cpp.fif fift/lib/Asm.fif OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/${ARG_DEST_CPP} ) add_custom_target(gen_fif_${ID} DEPENDS ${ARG_DEST_FIF} ${ARG_DEST_CPP}) @@ -355,12 +368,15 @@ if (NOT CMAKE_CROSSCOMPILING) GenFif(DEST smartcont/auto/wallet3-code SOURCE smartcont/wallet3-code.fc NAME wallet3) GenFif(DEST smartcont/auto/simple-wallet-code SOURCE smartcont/simple-wallet-code.fc NAME simple-wallet) GenFif(DEST smartcont/auto/highload-wallet-code SOURCE smartcont/highload-wallet-code.fc NAME highload-wallet) - GenFif(DEST smartcont/auto/highload-wallet-v2-code SOURCE smartcont/highload-wallet-v2-code.fc NAME highoad-wallet-v2) + GenFif(DEST smartcont/auto/highload-wallet-v2-code SOURCE smartcont/highload-wallet-v2-code.fc NAME highload-wallet-v2) GenFif(DEST smartcont/auto/elector-code SOURCE smartcont/elector-code.fc NAME elector-code) GenFif(DEST smartcont/auto/multisig-code SOURCE smartcont/multisig-code.fc NAME multisig) GenFif(DEST smartcont/auto/restricted-wallet-code SOURCE smartcont/restricted-wallet-code.fc NAME restricted-wallet) GenFif(DEST smartcont/auto/restricted-wallet2-code SOURCE smartcont/restricted-wallet2-code.fc NAME restricted-wallet2) + GenFif(DEST smartcont/auto/dns-manual-code SOURCE smartcont/dns-manual-code.fc NAME dns-manual) + GenFif(DEST smartcont/auto/dns-auto-code SOURCE smartcont/dns-auto-code.fc NAME dns-auto) + GenFif(DEST smartcont/auto/simple-wallet-ext-code SOURCE smartcont/simple-wallet-ext-code.fc NAME simple-wallet-ext) endif() @@ -387,5 +403,13 @@ if (WINGETOPT_FOUND) target_link_libraries_system(dump-block wingetopt) endif() +add_executable(adjust-block block/adjust-block.cpp) +target_include_directories(adjust-block PUBLIC $ + $) +target_link_libraries(adjust-block PUBLIC ton_crypto fift-lib ton_block) +if (WINGETOPT_FOUND) + target_link_libraries_system(dump-block wingetopt) +endif() + install(TARGETS fift func RUNTIME DESTINATION bin) install(DIRECTORY fift/lib/ DESTINATION lib/fift) diff --git a/submodules/ton/tonlib-src/crypto/block/adjust-block.cpp b/submodules/ton/tonlib-src/crypto/block/adjust-block.cpp new file mode 100644 index 0000000000..ba9d22cdae --- /dev/null +++ b/submodules/ton/tonlib-src/crypto/block/adjust-block.cpp @@ -0,0 +1,203 @@ +/* + This file is part of TON Blockchain source code. + + TON Blockchain is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + TON Blockchain is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TON Blockchain. If not, see . + + In addition, as a special exception, the copyright holders give permission + to link the code of portions of this program with the OpenSSL library. + You must obey the GNU General Public License in all respects for all + of the code used other than OpenSSL. If you modify file(s) with this + exception, you may extend this exception to your version of the file(s), + but you are not obligated to do so. If you do not wish to do so, delete this + exception statement from your version. If you delete this exception statement + from all source files in the program, then also delete it here. + + Copyright 2017-2019 Telegram Systems LLP +*/ +#include "block/block.h" +#include "vm/boc.h" +#include +#include "block-db.h" +#include "block-auto.h" +#include "block-parse.h" +#include "vm/cp0.h" +#include "td/utils/crypto.h" +#include + +using td::Ref; +using namespace std::literals::string_literals; + +int verbosity; + +struct IntError { + std::string err_msg; + IntError(std::string _msg) : err_msg(_msg) { + } + IntError(const char* _msg) : err_msg(_msg) { + } +}; + +int fatal(std::string str) { + std::cerr << "fatal error: " << str << std::endl; + std::exit(2); + return 2; +} + +static inline void fail_unless(td::Status res) { + if (res.is_error()) { + throw IntError{res.to_string()}; + } +} + +td::Ref load_block(std::string filename, ton::BlockIdExt& id) { + std::cerr << "loading block from bag-of-cell file " << filename << std::endl; + auto bytes_res = block::load_binary_file(filename); + if (bytes_res.is_error()) { + throw IntError{PSTRING() << "cannot load file `" << filename << "` : " << bytes_res.move_as_error()}; + } + ton::FileHash fhash; + td::sha256(bytes_res.ok(), fhash.as_slice()); + vm::BagOfCells boc; + auto res = boc.deserialize(bytes_res.move_as_ok()); + if (res.is_error()) { + throw IntError{PSTRING() << "cannot deserialize bag-of-cells " << res.move_as_error()}; + } + if (res.move_as_ok() <= 0 || boc.get_root_cell().is_null()) { + throw IntError{"cannot deserialize bag-of-cells"}; + } + auto root = boc.get_root_cell(); + std::vector prev; + ton::BlockIdExt mc_blkid; + bool after_split; + fail_unless(block::unpack_block_prev_blk_try(root, id, prev, mc_blkid, after_split, &id)); + id.file_hash = fhash; + std::cerr << "loaded block " << id.to_str() << std::endl; + return root; +} + +bool save_block(std::string filename, Ref root, ton::BlockIdExt& id) { + std::cerr << "saving block into bag-of-cell file " << filename << std::endl; + if (root.is_null()) { + throw IntError{"new block has no root"}; + } + id.root_hash = root->get_hash().bits(); + auto res = vm::std_boc_serialize(std::move(root), 31); + if (res.is_error()) { + throw IntError{PSTRING() << "cannot serialize modified block as a bag-of-cells: " + << res.move_as_error().to_string()}; + } + auto data = res.move_as_ok(); + td::sha256(data, id.file_hash.as_slice()); + auto res1 = block::save_binary_file(filename, std::move(data)); + if (res1.is_error()) { + throw IntError{PSTRING() << "cannot save file `" << filename << "` : " << res1}; + } + return true; +} + +Ref adjust_block(Ref root, int vseqno_incr, const ton::BlockIdExt& id) { + std::vector prev; + ton::BlockIdExt mc_blkid; + bool after_split; + fail_unless(block::unpack_block_prev_blk_try(root, id, prev, mc_blkid, after_split)); + std::cerr << "unpacked header of block " << id.to_str() << std::endl; + if (!id.is_masterchain()) { + throw IntError{"can modify only masterchain blocks"}; + } + block::gen::Block::Record blk; + block::gen::BlockInfo::Record info; + if (!(tlb::unpack_cell(root, blk) && tlb::unpack_cell(blk.info, info))) { + throw IntError{"cannot unpack block header"}; + } + if (!info.key_block) { + throw IntError{"can modify only key blocks"}; + } + info.vert_seqno_incr = true; + info.vert_seq_no += vseqno_incr; + if (!block::tlb::t_ExtBlkRef.pack_to(info.prev_vert_ref, id, info.end_lt)) { + throw IntError{"cannot pack prev_vert_ref"}; + } + if (!(tlb::pack_cell(blk.info, info) && tlb::pack_cell(root, blk))) { + throw IntError{"cannot pack block header"}; + } + return root; +} + +void usage() { + std::cout << "usage: adjust-block [-i] \n\tor adjust-block -h\n\tAdjusts block " + "loaded from by incrementing vert_seqno by (1 by default)\n"; + std::exit(3); +} + +int main(int argc, char* const argv[]) { + int i, vseqno_incr = 1; + int new_verbosity_level = VERBOSITY_NAME(INFO); + std::string in_fname, out_fname; + while ((i = getopt(argc, argv, "hi:v:")) != -1) { + switch (i) { + case 'h': + usage(); + break; + case 'i': + vseqno_incr = td::to_integer(td::Slice(optarg)); + CHECK(vseqno_incr > 0 && vseqno_incr < 1000); + break; + case 'v': + new_verbosity_level = VERBOSITY_NAME(FATAL) + (verbosity = td::to_integer(td::Slice(optarg))); + break; + default: + usage(); + break; + } + } + SET_VERBOSITY_LEVEL(new_verbosity_level); + if (argc != optind + 2) { + usage(); + return 2; + } + in_fname = argv[optind]; + out_fname = argv[optind + 1]; + try { + ton::BlockIdExt old_id, new_id; + auto root = load_block(in_fname, old_id); + if (root.is_null()) { + return fatal("cannot load BoC from file "s + in_fname); + } + bool ok = block::gen::t_Block.validate_ref(root); + if (!ok) { + return fatal("file `"s + in_fname + " does not contain a valid block"); + } + auto adjusted = adjust_block(root, vseqno_incr, old_id); + if (adjusted.is_null()) { + return fatal("cannot adjust block"); + } + ok = block::gen::t_Block.validate_ref(root); + if (!ok) { + return fatal("modified block is not valid"); + } + new_id = old_id; + if (!save_block(out_fname, adjusted, new_id)) { + return fatal("cannot save modified block to file `"s + out_fname + "`"); + } + std::cout << "old block id: " << old_id.to_str() << std::endl; + std::cout << "new block id: " << new_id.to_str() << std::endl; + } catch (IntError& err) { + std::cerr << "internal error: " << err.err_msg << std::endl; + return 1; + } catch (vm::VmError& err) { + std::cerr << "vm error: " << err.get_msg() << std::endl; + return 1; + } + return 0; +} diff --git a/submodules/ton/tonlib-src/crypto/block/block-auto.cpp b/submodules/ton/tonlib-src/crypto/block/block-auto.cpp index d3d666fb75..d2bf8aea89 100644 --- a/submodules/ton/tonlib-src/crypto/block/block-auto.cpp +++ b/submodules/ton/tonlib-src/crypto/block/block-auto.cpp @@ -14,11 +14,16 @@ // uses built-in type `uint` // uses built-in type `bits` // uses built-in type `int8` +// uses built-in type `uint13` // uses built-in type `uint15` +// uses built-in type `int16` // uses built-in type `uint16` // uses built-in type `int32` // uses built-in type `uint32` +// uses built-in type `uint63` +// uses built-in type `int64` // uses built-in type `uint64` +// uses built-in type `int257` // uses built-in type `bits256` namespace block { @@ -273,7 +278,7 @@ int BoolFalse::check_tag(const vm::CellSlice& cs) const { return cs.prefetch_ulong(1) == 0 ? bool_false : -1; } -bool BoolFalse::validate_skip(vm::CellSlice& cs, bool weak) const { +bool BoolFalse::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { return cs.fetch_ulong(1) == 0; } @@ -340,7 +345,7 @@ int BoolTrue::check_tag(const vm::CellSlice& cs) const { return cs.prefetch_ulong(1) == 1 ? bool_true : -1; } -bool BoolTrue::validate_skip(vm::CellSlice& cs, bool weak) const { +bool BoolTrue::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { return cs.fetch_ulong(1) == 1; } @@ -423,13 +428,13 @@ bool Maybe::skip(vm::CellSlice& cs) const { return false; } -bool Maybe::validate_skip(vm::CellSlice& cs, bool weak) const { +bool Maybe::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case nothing: return cs.advance(1); case just: return cs.advance(1) - && X_.validate_skip(cs, weak); + && X_.validate_skip(ops, cs, weak); } return false; } @@ -556,14 +561,14 @@ bool Either::skip(vm::CellSlice& cs) const { return false; } -bool Either::validate_skip(vm::CellSlice& cs, bool weak) const { +bool Either::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case left: return cs.advance(1) - && X_.validate_skip(cs, weak); + && X_.validate_skip(ops, cs, weak); case right: return cs.advance(1) - && Y_.validate_skip(cs, weak); + && Y_.validate_skip(ops, cs, weak); } return false; } @@ -684,9 +689,9 @@ bool Both::skip(vm::CellSlice& cs) const { && Y_.skip(cs); } -bool Both::validate_skip(vm::CellSlice& cs, bool weak) const { - return X_.validate_skip(cs, weak) - && Y_.validate_skip(cs, weak); +bool Both::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return X_.validate_skip(ops, cs, weak) + && Y_.validate_skip(ops, cs, weak); } bool Both::unpack(vm::CellSlice& cs, Both::Record& data) const { @@ -812,11 +817,11 @@ bool Hashmap::skip(vm::CellSlice& cs) const { && HashmapNode{m, X_}.skip(cs); } -bool Hashmap::validate_skip(vm::CellSlice& cs, bool weak) const { +bool Hashmap::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { int l, m; - return HmLabel{m_}.validate_skip(cs, weak, l) + return HmLabel{m_}.validate_skip(ops, cs, weak, l) && add_r1(m, l, m_) - && HashmapNode{m, X_}.validate_skip(cs, weak); + && HashmapNode{m, X_}.validate_skip(ops, cs, weak); } bool Hashmap::unpack(vm::CellSlice& cs, Hashmap::Record& data) const { @@ -889,16 +894,16 @@ bool HashmapNode::skip(vm::CellSlice& cs) const { return false; } -bool HashmapNode::validate_skip(vm::CellSlice& cs, bool weak) const { +bool HashmapNode::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case hmn_leaf: return m_ == 0 - && X_.validate_skip(cs, weak); + && X_.validate_skip(ops, cs, weak); case hmn_fork: { int n; return add_r1(n, 1, m_) - && Hashmap{n, X_}.validate_skip_ref(cs, weak) - && Hashmap{n, X_}.validate_skip_ref(cs, weak); + && Hashmap{n, X_}.validate_skip_ref(ops, cs, weak) + && Hashmap{n, X_}.validate_skip_ref(ops, cs, weak); } } return false; @@ -1077,12 +1082,12 @@ bool HmLabel::skip(vm::CellSlice& cs, int& m_) const { return false; } -bool HmLabel::validate_skip(vm::CellSlice& cs, bool weak) const { +bool HmLabel::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case hml_short: { int m_; return cs.advance(1) - && t_Unary.validate_skip(cs, weak, m_) + && t_Unary.validate_skip(ops, cs, weak, m_) && m_ <= n_ && cs.advance(m_); } @@ -1101,11 +1106,11 @@ bool HmLabel::validate_skip(vm::CellSlice& cs, bool weak) const { return false; } -bool HmLabel::validate_skip(vm::CellSlice& cs, bool weak, int& m_) const { +bool HmLabel::validate_skip(int* ops, vm::CellSlice& cs, bool weak, int& m_) const { switch (get_tag(cs)) { case hml_short: return cs.advance(1) - && t_Unary.validate_skip(cs, weak, m_) + && t_Unary.validate_skip(ops, cs, weak, m_) && m_ <= n_ && cs.advance(m_); case hml_long: @@ -1360,20 +1365,20 @@ bool Unary::skip(vm::CellSlice& cs, int& m_) const { return false; } -bool Unary::validate_skip(vm::CellSlice& cs, bool weak) const { +bool Unary::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case unary_zero: return cs.advance(1); case unary_succ: { int n; return cs.advance(1) - && validate_skip(cs, weak, n); + && validate_skip(ops, cs, weak, n); } } return false; } -bool Unary::validate_skip(vm::CellSlice& cs, bool weak, int& m_) const { +bool Unary::validate_skip(int* ops, vm::CellSlice& cs, bool weak, int& m_) const { switch (get_tag(cs)) { case unary_zero: return (m_ = 0) >= 0 @@ -1381,7 +1386,7 @@ bool Unary::validate_skip(vm::CellSlice& cs, bool weak, int& m_) const { case unary_succ: { int n; return cs.advance(1) - && validate_skip(cs, weak, n) + && validate_skip(ops, cs, weak, n) && (m_ = n + 1) >= 0; } } @@ -1545,13 +1550,13 @@ bool HashmapE::skip(vm::CellSlice& cs) const { return false; } -bool HashmapE::validate_skip(vm::CellSlice& cs, bool weak) const { +bool HashmapE::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case hme_empty: return cs.advance(1); case hme_root: return cs.advance(1) - && Hashmap{m_, X_}.validate_skip_ref(cs, weak); + && Hashmap{m_, X_}.validate_skip_ref(ops, cs, weak); } return false; } @@ -1666,8 +1671,8 @@ bool BitstringSet::skip(vm::CellSlice& cs) const { return Hashmap{m_, t_True}.skip(cs); } -bool BitstringSet::validate_skip(vm::CellSlice& cs, bool weak) const { - return Hashmap{m_, t_True}.validate_skip(cs, weak); +bool BitstringSet::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return Hashmap{m_, t_True}.validate_skip(ops, cs, weak); } bool BitstringSet::unpack(vm::CellSlice& cs, BitstringSet::Record& data) const { @@ -1733,11 +1738,11 @@ bool HashmapAug::skip(vm::CellSlice& cs) const { && HashmapAugNode{m, X_, Y_}.skip(cs); } -bool HashmapAug::validate_skip(vm::CellSlice& cs, bool weak) const { +bool HashmapAug::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { int l, m; - return HmLabel{m_}.validate_skip(cs, weak, l) + return HmLabel{m_}.validate_skip(ops, cs, weak, l) && add_r1(m, l, m_) - && HashmapAugNode{m, X_, Y_}.validate_skip(cs, weak); + && HashmapAugNode{m, X_, Y_}.validate_skip(ops, cs, weak); } bool HashmapAug::unpack(vm::CellSlice& cs, HashmapAug::Record& data) const { @@ -1812,18 +1817,18 @@ bool HashmapAugNode::skip(vm::CellSlice& cs) const { return false; } -bool HashmapAugNode::validate_skip(vm::CellSlice& cs, bool weak) const { +bool HashmapAugNode::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case ahmn_leaf: return m_ == 0 - && Y_.validate_skip(cs, weak) - && X_.validate_skip(cs, weak); + && Y_.validate_skip(ops, cs, weak) + && X_.validate_skip(ops, cs, weak); case ahmn_fork: { int n; return add_r1(n, 1, m_) - && HashmapAug{n, X_, Y_}.validate_skip_ref(cs, weak) - && HashmapAug{n, X_, Y_}.validate_skip_ref(cs, weak) - && Y_.validate_skip(cs, weak); + && HashmapAug{n, X_, Y_}.validate_skip_ref(ops, cs, weak) + && HashmapAug{n, X_, Y_}.validate_skip_ref(ops, cs, weak) + && Y_.validate_skip(ops, cs, weak); } } return false; @@ -1954,15 +1959,15 @@ bool HashmapAugE::skip(vm::CellSlice& cs) const { return false; } -bool HashmapAugE::validate_skip(vm::CellSlice& cs, bool weak) const { +bool HashmapAugE::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case ahme_empty: return cs.advance(1) - && Y_.validate_skip(cs, weak); + && Y_.validate_skip(ops, cs, weak); case ahme_root: return cs.advance(1) - && HashmapAug{m_, X_, Y_}.validate_skip_ref(cs, weak) - && Y_.validate_skip(cs, weak); + && HashmapAug{m_, X_, Y_}.validate_skip_ref(ops, cs, weak) + && Y_.validate_skip(ops, cs, weak); } return false; } @@ -2093,11 +2098,11 @@ bool VarHashmap::skip(vm::CellSlice& cs) const { && VarHashmapNode{m, X_}.skip(cs); } -bool VarHashmap::validate_skip(vm::CellSlice& cs, bool weak) const { +bool VarHashmap::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { int l, m; - return HmLabel{m_}.validate_skip(cs, weak, l) + return HmLabel{m_}.validate_skip(ops, cs, weak, l) && add_r1(m, l, m_) - && VarHashmapNode{m, X_}.validate_skip(cs, weak); + && VarHashmapNode{m, X_}.validate_skip(ops, cs, weak); } bool VarHashmap::unpack(vm::CellSlice& cs, VarHashmap::Record& data) const { @@ -2176,25 +2181,25 @@ bool VarHashmapNode::skip(vm::CellSlice& cs) const { return false; } -bool VarHashmapNode::validate_skip(vm::CellSlice& cs, bool weak) const { +bool VarHashmapNode::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case vhmn_leaf: return cs.advance(2) - && X_.validate_skip(cs, weak); + && X_.validate_skip(ops, cs, weak); case vhmn_fork: { int n; return add_r1(n, 1, m_) && cs.advance(2) - && VarHashmap{n, X_}.validate_skip_ref(cs, weak) - && VarHashmap{n, X_}.validate_skip_ref(cs, weak) - && Maybe{X_}.validate_skip(cs, weak); + && VarHashmap{n, X_}.validate_skip_ref(ops, cs, weak) + && VarHashmap{n, X_}.validate_skip_ref(ops, cs, weak) + && Maybe{X_}.validate_skip(ops, cs, weak); } case vhmn_cont: { int n; return add_r1(n, 1, m_) && cs.advance(2) - && VarHashmap{n, X_}.validate_skip_ref(cs, weak) - && X_.validate_skip(cs, weak); + && VarHashmap{n, X_}.validate_skip_ref(ops, cs, weak) + && X_.validate_skip(ops, cs, weak); } } return false; @@ -2360,13 +2365,13 @@ bool VarHashmapE::skip(vm::CellSlice& cs) const { return false; } -bool VarHashmapE::validate_skip(vm::CellSlice& cs, bool weak) const { +bool VarHashmapE::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case vhme_empty: return cs.advance(1); case vhme_root: return cs.advance(1) - && VarHashmap{m_, X_}.validate_skip_ref(cs, weak); + && VarHashmap{m_, X_}.validate_skip_ref(ops, cs, weak); } return false; } @@ -2484,11 +2489,11 @@ bool PfxHashmap::skip(vm::CellSlice& cs) const { && PfxHashmapNode{m, X_}.skip(cs); } -bool PfxHashmap::validate_skip(vm::CellSlice& cs, bool weak) const { +bool PfxHashmap::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { int l, m; - return HmLabel{m_}.validate_skip(cs, weak, l) + return HmLabel{m_}.validate_skip(ops, cs, weak, l) && add_r1(m, l, m_) - && PfxHashmapNode{m, X_}.validate_skip(cs, weak); + && PfxHashmapNode{m, X_}.validate_skip(ops, cs, weak); } bool PfxHashmap::unpack(vm::CellSlice& cs, PfxHashmap::Record& data) const { @@ -2556,17 +2561,17 @@ bool PfxHashmapNode::skip(vm::CellSlice& cs) const { return false; } -bool PfxHashmapNode::validate_skip(vm::CellSlice& cs, bool weak) const { +bool PfxHashmapNode::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case phmn_leaf: return cs.advance(1) - && X_.validate_skip(cs, weak); + && X_.validate_skip(ops, cs, weak); case phmn_fork: { int n; return add_r1(n, 1, m_) && cs.advance(1) - && PfxHashmap{n, X_}.validate_skip_ref(cs, weak) - && PfxHashmap{n, X_}.validate_skip_ref(cs, weak); + && PfxHashmap{n, X_}.validate_skip_ref(ops, cs, weak) + && PfxHashmap{n, X_}.validate_skip_ref(ops, cs, weak); } } return false; @@ -2714,13 +2719,13 @@ bool PfxHashmapE::skip(vm::CellSlice& cs) const { return false; } -bool PfxHashmapE::validate_skip(vm::CellSlice& cs, bool weak) const { +bool PfxHashmapE::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case phme_empty: return cs.advance(1); case phme_root: return cs.advance(1) - && PfxHashmap{m_, X_}.validate_skip_ref(cs, weak); + && PfxHashmap{m_, X_}.validate_skip_ref(ops, cs, weak); } return false; } @@ -2851,7 +2856,7 @@ bool MsgAddressExt::skip(vm::CellSlice& cs) const { return false; } -bool MsgAddressExt::validate_skip(vm::CellSlice& cs, bool weak) const { +bool MsgAddressExt::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case addr_none: return cs.advance(2); @@ -2984,7 +2989,7 @@ bool Anycast::skip(vm::CellSlice& cs) const { && cs.advance(depth); } -bool Anycast::validate_skip(vm::CellSlice& cs, bool weak) const { +bool Anycast::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { int depth; return cs.fetch_uint_leq(30, depth) && 1 <= depth @@ -3082,16 +3087,16 @@ bool MsgAddressInt::skip(vm::CellSlice& cs) const { return false; } -bool MsgAddressInt::validate_skip(vm::CellSlice& cs, bool weak) const { +bool MsgAddressInt::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case addr_std: return cs.advance(2) - && t_Maybe_Anycast.validate_skip(cs, weak) + && t_Maybe_Anycast.validate_skip(ops, cs, weak) && cs.advance(264); case addr_var: { int addr_len; return cs.advance(2) - && t_Maybe_Anycast.validate_skip(cs, weak) + && t_Maybe_Anycast.validate_skip(ops, cs, weak) && cs.fetch_uint_to(9, addr_len) && cs.advance(32) && cs.advance(addr_len); @@ -3229,12 +3234,12 @@ bool MsgAddress::skip(vm::CellSlice& cs) const { return false; } -bool MsgAddress::validate_skip(vm::CellSlice& cs, bool weak) const { +bool MsgAddress::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case cons1: - return t_MsgAddressInt.validate_skip(cs, weak); + return t_MsgAddressInt.validate_skip(ops, cs, weak); case cons2: - return t_MsgAddressExt.validate_skip(cs, weak); + return t_MsgAddressExt.validate_skip(ops, cs, weak); } return false; } @@ -3347,7 +3352,7 @@ bool VarUInteger::skip(vm::CellSlice& cs) const { && cs.advance(8 * len); } -bool VarUInteger::validate_skip(vm::CellSlice& cs, bool weak) const { +bool VarUInteger::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { int len; return cs.fetch_uint_less(m_, len) && cs.advance(8 * len); @@ -3421,7 +3426,7 @@ bool VarInteger::skip(vm::CellSlice& cs) const { && cs.advance(8 * len); } -bool VarInteger::validate_skip(vm::CellSlice& cs, bool weak) const { +bool VarInteger::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { int len; return cs.fetch_uint_less(m_, len) && cs.advance(8 * len); @@ -3493,8 +3498,8 @@ bool Grams::skip(vm::CellSlice& cs) const { return t_VarUInteger_16.skip(cs); } -bool Grams::validate_skip(vm::CellSlice& cs, bool weak) const { - return t_VarUInteger_16.validate_skip(cs, weak); +bool Grams::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_VarUInteger_16.validate_skip(ops, cs, weak); } bool Grams::unpack(vm::CellSlice& cs, Grams::Record& data) const { @@ -3556,8 +3561,8 @@ bool ExtraCurrencyCollection::skip(vm::CellSlice& cs) const { return t_HashmapE_32_VarUInteger_32.skip(cs); } -bool ExtraCurrencyCollection::validate_skip(vm::CellSlice& cs, bool weak) const { - return t_HashmapE_32_VarUInteger_32.validate_skip(cs, weak); +bool ExtraCurrencyCollection::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_HashmapE_32_VarUInteger_32.validate_skip(ops, cs, weak); } bool ExtraCurrencyCollection::unpack(vm::CellSlice& cs, ExtraCurrencyCollection::Record& data) const { @@ -3620,9 +3625,9 @@ bool CurrencyCollection::skip(vm::CellSlice& cs) const { && t_ExtraCurrencyCollection.skip(cs); } -bool CurrencyCollection::validate_skip(vm::CellSlice& cs, bool weak) const { - return t_Grams.validate_skip(cs, weak) - && t_ExtraCurrencyCollection.validate_skip(cs, weak); +bool CurrencyCollection::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_Grams.validate_skip(ops, cs, weak) + && t_ExtraCurrencyCollection.validate_skip(ops, cs, weak); } bool CurrencyCollection::unpack(vm::CellSlice& cs, CurrencyCollection::Record& data) const { @@ -3720,25 +3725,25 @@ bool CommonMsgInfo::skip(vm::CellSlice& cs) const { return false; } -bool CommonMsgInfo::validate_skip(vm::CellSlice& cs, bool weak) const { +bool CommonMsgInfo::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case int_msg_info: return cs.advance(4) - && t_MsgAddressInt.validate_skip(cs, weak) - && t_MsgAddressInt.validate_skip(cs, weak) - && t_CurrencyCollection.validate_skip(cs, weak) - && t_Grams.validate_skip(cs, weak) - && t_Grams.validate_skip(cs, weak) + && t_MsgAddressInt.validate_skip(ops, cs, weak) + && t_MsgAddressInt.validate_skip(ops, cs, weak) + && t_CurrencyCollection.validate_skip(ops, cs, weak) + && t_Grams.validate_skip(ops, cs, weak) + && t_Grams.validate_skip(ops, cs, weak) && cs.advance(96); case ext_in_msg_info: return cs.advance(2) - && t_MsgAddressExt.validate_skip(cs, weak) - && t_MsgAddressInt.validate_skip(cs, weak) - && t_Grams.validate_skip(cs, weak); + && t_MsgAddressExt.validate_skip(ops, cs, weak) + && t_MsgAddressInt.validate_skip(ops, cs, weak) + && t_Grams.validate_skip(ops, cs, weak); case ext_out_msg_info: return cs.advance(2) - && t_MsgAddressInt.validate_skip(cs, weak) - && t_MsgAddressExt.validate_skip(cs, weak) + && t_MsgAddressInt.validate_skip(ops, cs, weak) + && t_MsgAddressExt.validate_skip(ops, cs, weak) && cs.advance(96); } return false; @@ -3942,20 +3947,20 @@ bool CommonMsgInfoRelaxed::skip(vm::CellSlice& cs) const { return false; } -bool CommonMsgInfoRelaxed::validate_skip(vm::CellSlice& cs, bool weak) const { +bool CommonMsgInfoRelaxed::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case int_msg_info: return cs.advance(4) - && t_MsgAddress.validate_skip(cs, weak) - && t_MsgAddressInt.validate_skip(cs, weak) - && t_CurrencyCollection.validate_skip(cs, weak) - && t_Grams.validate_skip(cs, weak) - && t_Grams.validate_skip(cs, weak) + && t_MsgAddress.validate_skip(ops, cs, weak) + && t_MsgAddressInt.validate_skip(ops, cs, weak) + && t_CurrencyCollection.validate_skip(ops, cs, weak) + && t_Grams.validate_skip(ops, cs, weak) + && t_Grams.validate_skip(ops, cs, weak) && cs.advance(96); case ext_out_msg_info: return cs.fetch_ulong(2) == 3 - && t_MsgAddress.validate_skip(cs, weak) - && t_MsgAddressExt.validate_skip(cs, weak) + && t_MsgAddress.validate_skip(ops, cs, weak) + && t_MsgAddressExt.validate_skip(ops, cs, weak) && cs.advance(96); } return false; @@ -4139,12 +4144,12 @@ bool StateInit::skip(vm::CellSlice& cs) const { && t_HashmapE_256_SimpleLib.skip(cs); } -bool StateInit::validate_skip(vm::CellSlice& cs, bool weak) const { - return t_Maybe_natwidth_5.validate_skip(cs, weak) - && t_Maybe_TickTock.validate_skip(cs, weak) - && t_Maybe_Ref_Cell.validate_skip(cs, weak) - && t_Maybe_Ref_Cell.validate_skip(cs, weak) - && t_HashmapE_256_SimpleLib.validate_skip(cs, weak); +bool StateInit::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_Maybe_natwidth_5.validate_skip(ops, cs, weak) + && t_Maybe_TickTock.validate_skip(ops, cs, weak) + && t_Maybe_Ref_Cell.validate_skip(ops, cs, weak) + && t_Maybe_Ref_Cell.validate_skip(ops, cs, weak) + && t_HashmapE_256_SimpleLib.validate_skip(ops, cs, weak); } bool StateInit::unpack(vm::CellSlice& cs, StateInit::Record& data) const { @@ -4199,7 +4204,7 @@ int SimpleLib::check_tag(const vm::CellSlice& cs) const { return simple_lib; } -bool SimpleLib::validate_skip(vm::CellSlice& cs, bool weak) const { +bool SimpleLib::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { return cs.advance_ext(0x10001); } @@ -4269,10 +4274,10 @@ bool Message::skip(vm::CellSlice& cs) const { && Either{X_, RefT{X_}}.skip(cs); } -bool Message::validate_skip(vm::CellSlice& cs, bool weak) const { - return t_CommonMsgInfo.validate_skip(cs, weak) - && t_Maybe_Either_StateInit_Ref_StateInit.validate_skip(cs, weak) - && Either{X_, RefT{X_}}.validate_skip(cs, weak); +bool Message::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_CommonMsgInfo.validate_skip(ops, cs, weak) + && t_Maybe_Either_StateInit_Ref_StateInit.validate_skip(ops, cs, weak) + && Either{X_, RefT{X_}}.validate_skip(ops, cs, weak); } bool Message::unpack(vm::CellSlice& cs, Message::Record& data) const { @@ -4347,10 +4352,10 @@ bool MessageRelaxed::skip(vm::CellSlice& cs) const { && Either{X_, RefT{X_}}.skip(cs); } -bool MessageRelaxed::validate_skip(vm::CellSlice& cs, bool weak) const { - return t_CommonMsgInfoRelaxed.validate_skip(cs, weak) - && t_Maybe_Either_StateInit_Ref_StateInit.validate_skip(cs, weak) - && Either{X_, RefT{X_}}.validate_skip(cs, weak); +bool MessageRelaxed::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_CommonMsgInfoRelaxed.validate_skip(ops, cs, weak) + && t_Maybe_Either_StateInit_Ref_StateInit.validate_skip(ops, cs, weak) + && Either{X_, RefT{X_}}.validate_skip(ops, cs, weak); } bool MessageRelaxed::unpack(vm::CellSlice& cs, MessageRelaxed::Record& data) const { @@ -4441,7 +4446,7 @@ bool IntermediateAddress::skip(vm::CellSlice& cs) const { return false; } -bool IntermediateAddress::validate_skip(vm::CellSlice& cs, bool weak) const { +bool IntermediateAddress::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case interm_addr_regular: { int use_dest_bits; @@ -4635,12 +4640,12 @@ bool MsgEnvelope::skip(vm::CellSlice& cs) const { && cs.advance_refs(1); } -bool MsgEnvelope::validate_skip(vm::CellSlice& cs, bool weak) const { +bool MsgEnvelope::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { return cs.fetch_ulong(4) == 4 - && t_IntermediateAddress.validate_skip(cs, weak) - && t_IntermediateAddress.validate_skip(cs, weak) - && t_Grams.validate_skip(cs, weak) - && t_Message_Any.validate_skip_ref(cs, weak); + && t_IntermediateAddress.validate_skip(ops, cs, weak) + && t_IntermediateAddress.validate_skip(ops, cs, weak) + && t_Grams.validate_skip(ops, cs, weak) + && t_Message_Any.validate_skip_ref(ops, cs, weak); } bool MsgEnvelope::unpack(vm::CellSlice& cs, MsgEnvelope::Record& data) const { @@ -4739,43 +4744,43 @@ bool InMsg::skip(vm::CellSlice& cs) const { return false; } -bool InMsg::validate_skip(vm::CellSlice& cs, bool weak) const { +bool InMsg::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case msg_import_ext: return cs.fetch_ulong(3) == 0 - && t_Message_Any.validate_skip_ref(cs, weak) - && t_Transaction.validate_skip_ref(cs, weak); + && t_Message_Any.validate_skip_ref(ops, cs, weak) + && t_Transaction.validate_skip_ref(ops, cs, weak); case msg_import_ihr: return cs.advance(3) - && t_Message_Any.validate_skip_ref(cs, weak) - && t_Transaction.validate_skip_ref(cs, weak) - && t_Grams.validate_skip(cs, weak) + && t_Message_Any.validate_skip_ref(ops, cs, weak) + && t_Transaction.validate_skip_ref(ops, cs, weak) + && t_Grams.validate_skip(ops, cs, weak) && cs.advance_refs(1); case msg_import_imm: return cs.advance(3) - && t_MsgEnvelope.validate_skip_ref(cs, weak) - && t_Transaction.validate_skip_ref(cs, weak) - && t_Grams.validate_skip(cs, weak); + && t_MsgEnvelope.validate_skip_ref(ops, cs, weak) + && t_Transaction.validate_skip_ref(ops, cs, weak) + && t_Grams.validate_skip(ops, cs, weak); case msg_import_fin: return cs.advance(3) - && t_MsgEnvelope.validate_skip_ref(cs, weak) - && t_Transaction.validate_skip_ref(cs, weak) - && t_Grams.validate_skip(cs, weak); + && t_MsgEnvelope.validate_skip_ref(ops, cs, weak) + && t_Transaction.validate_skip_ref(ops, cs, weak) + && t_Grams.validate_skip(ops, cs, weak); case msg_import_tr: return cs.advance(3) - && t_MsgEnvelope.validate_skip_ref(cs, weak) - && t_MsgEnvelope.validate_skip_ref(cs, weak) - && t_Grams.validate_skip(cs, weak); + && t_MsgEnvelope.validate_skip_ref(ops, cs, weak) + && t_MsgEnvelope.validate_skip_ref(ops, cs, weak) + && t_Grams.validate_skip(ops, cs, weak); case msg_discard_fin: return cs.advance(3) - && t_MsgEnvelope.validate_skip_ref(cs, weak) + && t_MsgEnvelope.validate_skip_ref(ops, cs, weak) && cs.advance(64) - && t_Grams.validate_skip(cs, weak); + && t_Grams.validate_skip(ops, cs, weak); case msg_discard_tr: return cs.advance(3) - && t_MsgEnvelope.validate_skip_ref(cs, weak) + && t_MsgEnvelope.validate_skip_ref(ops, cs, weak) && cs.advance(64) - && t_Grams.validate_skip(cs, weak) + && t_Grams.validate_skip(ops, cs, weak) && cs.advance_refs(1); } return false; @@ -5172,9 +5177,9 @@ bool ImportFees::skip(vm::CellSlice& cs) const { && t_CurrencyCollection.skip(cs); } -bool ImportFees::validate_skip(vm::CellSlice& cs, bool weak) const { - return t_Grams.validate_skip(cs, weak) - && t_CurrencyCollection.validate_skip(cs, weak); +bool ImportFees::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_Grams.validate_skip(ops, cs, weak) + && t_CurrencyCollection.validate_skip(ops, cs, weak); } bool ImportFees::unpack(vm::CellSlice& cs, ImportFees::Record& data) const { @@ -5242,8 +5247,8 @@ bool InMsgDescr::skip(vm::CellSlice& cs) const { return t_HashmapAugE_256_InMsg_ImportFees.skip(cs); } -bool InMsgDescr::validate_skip(vm::CellSlice& cs, bool weak) const { - return t_HashmapAugE_256_InMsg_ImportFees.validate_skip(cs, weak); +bool InMsgDescr::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_HashmapAugE_256_InMsg_ImportFees.validate_skip(ops, cs, weak); } bool InMsgDescr::unpack(vm::CellSlice& cs, InMsgDescr::Record& data) const { @@ -5338,37 +5343,37 @@ bool OutMsg::skip(vm::CellSlice& cs) const { return false; } -bool OutMsg::validate_skip(vm::CellSlice& cs, bool weak) const { +bool OutMsg::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case msg_export_ext: return cs.advance(3) - && t_Message_Any.validate_skip_ref(cs, weak) - && t_Transaction.validate_skip_ref(cs, weak); + && t_Message_Any.validate_skip_ref(ops, cs, weak) + && t_Transaction.validate_skip_ref(ops, cs, weak); case msg_export_imm: return cs.advance(3) - && t_MsgEnvelope.validate_skip_ref(cs, weak) - && t_Transaction.validate_skip_ref(cs, weak) - && t_InMsg.validate_skip_ref(cs, weak); + && t_MsgEnvelope.validate_skip_ref(ops, cs, weak) + && t_Transaction.validate_skip_ref(ops, cs, weak) + && t_InMsg.validate_skip_ref(ops, cs, weak); case msg_export_new: return cs.advance(3) - && t_MsgEnvelope.validate_skip_ref(cs, weak) - && t_Transaction.validate_skip_ref(cs, weak); + && t_MsgEnvelope.validate_skip_ref(ops, cs, weak) + && t_Transaction.validate_skip_ref(ops, cs, weak); case msg_export_tr: return cs.advance(3) - && t_MsgEnvelope.validate_skip_ref(cs, weak) - && t_InMsg.validate_skip_ref(cs, weak); + && t_MsgEnvelope.validate_skip_ref(ops, cs, weak) + && t_InMsg.validate_skip_ref(ops, cs, weak); case msg_export_deq: return cs.advance(3) - && t_MsgEnvelope.validate_skip_ref(cs, weak) + && t_MsgEnvelope.validate_skip_ref(ops, cs, weak) && cs.advance(64); case msg_export_tr_req: return cs.advance(3) - && t_MsgEnvelope.validate_skip_ref(cs, weak) - && t_InMsg.validate_skip_ref(cs, weak); + && t_MsgEnvelope.validate_skip_ref(ops, cs, weak) + && t_InMsg.validate_skip_ref(ops, cs, weak); case msg_export_deq_imm: return cs.fetch_ulong(3) == 4 - && t_MsgEnvelope.validate_skip_ref(cs, weak) - && t_InMsg.validate_skip_ref(cs, weak); + && t_MsgEnvelope.validate_skip_ref(ops, cs, weak) + && t_InMsg.validate_skip_ref(ops, cs, weak); } return false; } @@ -5772,9 +5777,9 @@ int EnqueuedMsg::check_tag(const vm::CellSlice& cs) const { return cons1; } -bool EnqueuedMsg::validate_skip(vm::CellSlice& cs, bool weak) const { +bool EnqueuedMsg::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { return cs.advance(64) - && t_MsgEnvelope.validate_skip_ref(cs, weak); + && t_MsgEnvelope.validate_skip_ref(ops, cs, weak); } bool EnqueuedMsg::unpack(vm::CellSlice& cs, EnqueuedMsg::Record& data) const { @@ -5841,8 +5846,8 @@ bool OutMsgDescr::skip(vm::CellSlice& cs) const { return t_HashmapAugE_256_OutMsg_CurrencyCollection.skip(cs); } -bool OutMsgDescr::validate_skip(vm::CellSlice& cs, bool weak) const { - return t_HashmapAugE_256_OutMsg_CurrencyCollection.validate_skip(cs, weak); +bool OutMsgDescr::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_HashmapAugE_256_OutMsg_CurrencyCollection.validate_skip(ops, cs, weak); } bool OutMsgDescr::unpack(vm::CellSlice& cs, OutMsgDescr::Record& data) const { @@ -5904,8 +5909,8 @@ bool OutMsgQueue::skip(vm::CellSlice& cs) const { return t_HashmapAugE_352_EnqueuedMsg_uint64.skip(cs); } -bool OutMsgQueue::validate_skip(vm::CellSlice& cs, bool weak) const { - return t_HashmapAugE_352_EnqueuedMsg_uint64.validate_skip(cs, weak); +bool OutMsgQueue::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_HashmapAugE_352_EnqueuedMsg_uint64.validate_skip(ops, cs, weak); } bool OutMsgQueue::unpack(vm::CellSlice& cs, OutMsgQueue::Record& data) const { @@ -6026,8 +6031,8 @@ bool ProcessedInfo::skip(vm::CellSlice& cs) const { return t_HashmapE_96_ProcessedUpto.skip(cs); } -bool ProcessedInfo::validate_skip(vm::CellSlice& cs, bool weak) const { - return t_HashmapE_96_ProcessedUpto.validate_skip(cs, weak); +bool ProcessedInfo::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_HashmapE_96_ProcessedUpto.validate_skip(ops, cs, weak); } bool ProcessedInfo::unpack(vm::CellSlice& cs, ProcessedInfo::Record& data) const { @@ -6143,8 +6148,8 @@ bool IhrPendingInfo::skip(vm::CellSlice& cs) const { return t_HashmapE_320_IhrPendingSince.skip(cs); } -bool IhrPendingInfo::validate_skip(vm::CellSlice& cs, bool weak) const { - return t_HashmapE_320_IhrPendingSince.validate_skip(cs, weak); +bool IhrPendingInfo::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_HashmapE_320_IhrPendingSince.validate_skip(ops, cs, weak); } bool IhrPendingInfo::unpack(vm::CellSlice& cs, IhrPendingInfo::Record& data) const { @@ -6208,10 +6213,10 @@ bool OutMsgQueueInfo::skip(vm::CellSlice& cs) const { && t_IhrPendingInfo.skip(cs); } -bool OutMsgQueueInfo::validate_skip(vm::CellSlice& cs, bool weak) const { - return t_OutMsgQueue.validate_skip(cs, weak) - && t_ProcessedInfo.validate_skip(cs, weak) - && t_IhrPendingInfo.validate_skip(cs, weak); +bool OutMsgQueueInfo::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_OutMsgQueue.validate_skip(ops, cs, weak) + && t_ProcessedInfo.validate_skip(ops, cs, weak) + && t_IhrPendingInfo.validate_skip(ops, cs, weak); } bool OutMsgQueueInfo::unpack(vm::CellSlice& cs, OutMsgQueueInfo::Record& data) const { @@ -6287,10 +6292,10 @@ bool StorageUsed::skip(vm::CellSlice& cs) const { && t_VarUInteger_7.skip(cs); } -bool StorageUsed::validate_skip(vm::CellSlice& cs, bool weak) const { - return t_VarUInteger_7.validate_skip(cs, weak) - && t_VarUInteger_7.validate_skip(cs, weak) - && t_VarUInteger_7.validate_skip(cs, weak); +bool StorageUsed::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_VarUInteger_7.validate_skip(ops, cs, weak) + && t_VarUInteger_7.validate_skip(ops, cs, weak) + && t_VarUInteger_7.validate_skip(ops, cs, weak); } bool StorageUsed::unpack(vm::CellSlice& cs, StorageUsed::Record& data) const { @@ -6365,9 +6370,9 @@ bool StorageUsedShort::skip(vm::CellSlice& cs) const { && t_VarUInteger_7.skip(cs); } -bool StorageUsedShort::validate_skip(vm::CellSlice& cs, bool weak) const { - return t_VarUInteger_7.validate_skip(cs, weak) - && t_VarUInteger_7.validate_skip(cs, weak); +bool StorageUsedShort::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_VarUInteger_7.validate_skip(ops, cs, weak) + && t_VarUInteger_7.validate_skip(ops, cs, weak); } bool StorageUsedShort::unpack(vm::CellSlice& cs, StorageUsedShort::Record& data) const { @@ -6437,10 +6442,10 @@ bool StorageInfo::skip(vm::CellSlice& cs) const { && t_Maybe_Grams.skip(cs); } -bool StorageInfo::validate_skip(vm::CellSlice& cs, bool weak) const { - return t_StorageUsed.validate_skip(cs, weak) +bool StorageInfo::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_StorageUsed.validate_skip(ops, cs, weak) && cs.advance(32) - && t_Maybe_Grams.validate_skip(cs, weak); + && t_Maybe_Grams.validate_skip(ops, cs, weak); } bool StorageInfo::unpack(vm::CellSlice& cs, StorageInfo::Record& data) const { @@ -6528,15 +6533,15 @@ bool Account::skip(vm::CellSlice& cs) const { return false; } -bool Account::validate_skip(vm::CellSlice& cs, bool weak) const { +bool Account::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case account_none: return cs.advance(1); case account: return cs.advance(1) - && t_MsgAddressInt.validate_skip(cs, weak) - && t_StorageInfo.validate_skip(cs, weak) - && t_AccountStorage.validate_skip(cs, weak); + && t_MsgAddressInt.validate_skip(ops, cs, weak) + && t_StorageInfo.validate_skip(ops, cs, weak) + && t_AccountStorage.validate_skip(ops, cs, weak); } return false; } @@ -6664,10 +6669,10 @@ bool AccountStorage::skip(vm::CellSlice& cs) const { && t_AccountState.skip(cs); } -bool AccountStorage::validate_skip(vm::CellSlice& cs, bool weak) const { +bool AccountStorage::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { return cs.advance(64) - && t_CurrencyCollection.validate_skip(cs, weak) - && t_AccountState.validate_skip(cs, weak); + && t_CurrencyCollection.validate_skip(ops, cs, weak) + && t_AccountState.validate_skip(ops, cs, weak); } bool AccountStorage::unpack(vm::CellSlice& cs, AccountStorage::Record& data) const { @@ -6759,13 +6764,13 @@ bool AccountState::skip(vm::CellSlice& cs) const { return false; } -bool AccountState::validate_skip(vm::CellSlice& cs, bool weak) const { +bool AccountState::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case account_uninit: return cs.advance(2); case account_active: return cs.advance(1) - && t_StateInit.validate_skip(cs, weak); + && t_StateInit.validate_skip(ops, cs, weak); case account_frozen: return cs.advance(258); } @@ -7123,8 +7128,8 @@ int ShardAccount::check_tag(const vm::CellSlice& cs) const { return account_descr; } -bool ShardAccount::validate_skip(vm::CellSlice& cs, bool weak) const { - return t_Account.validate_skip_ref(cs, weak) +bool ShardAccount::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_Account.validate_skip_ref(ops, cs, weak) && cs.advance(320); } @@ -7198,10 +7203,10 @@ bool DepthBalanceInfo::skip(vm::CellSlice& cs) const { && t_CurrencyCollection.skip(cs); } -bool DepthBalanceInfo::validate_skip(vm::CellSlice& cs, bool weak) const { +bool DepthBalanceInfo::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { int split_depth; return cs.fetch_uint_leq(30, split_depth) - && t_CurrencyCollection.validate_skip(cs, weak); + && t_CurrencyCollection.validate_skip(ops, cs, weak); } bool DepthBalanceInfo::unpack(vm::CellSlice& cs, DepthBalanceInfo::Record& data) const { @@ -7270,8 +7275,8 @@ bool ShardAccounts::skip(vm::CellSlice& cs) const { return t_HashmapAugE_256_ShardAccount_DepthBalanceInfo.skip(cs); } -bool ShardAccounts::validate_skip(vm::CellSlice& cs, bool weak) const { - return t_HashmapAugE_256_ShardAccount_DepthBalanceInfo.validate_skip(cs, weak); +bool ShardAccounts::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_HashmapAugE_256_ShardAccount_DepthBalanceInfo.validate_skip(ops, cs, weak); } bool ShardAccounts::unpack(vm::CellSlice& cs, ShardAccounts::Record& data) const { @@ -7334,9 +7339,9 @@ bool Transaction_aux::skip(vm::CellSlice& cs) const { && t_HashmapE_15_Ref_Message_Any.skip(cs); } -bool Transaction_aux::validate_skip(vm::CellSlice& cs, bool weak) const { - return t_Maybe_Ref_Message_Any.validate_skip(cs, weak) - && t_HashmapE_15_Ref_Message_Any.validate_skip(cs, weak); +bool Transaction_aux::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_Maybe_Ref_Message_Any.validate_skip(ops, cs, weak) + && t_HashmapE_15_Ref_Message_Any.validate_skip(ops, cs, weak); } bool Transaction_aux::unpack(vm::CellSlice& cs, Transaction_aux::Record& data) const { @@ -7407,13 +7412,13 @@ bool Transaction::skip(vm::CellSlice& cs) const { && cs.advance_refs(2); } -bool Transaction::validate_skip(vm::CellSlice& cs, bool weak) const { +bool Transaction::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { return cs.fetch_ulong(4) == 7 && cs.advance(691) - && t_Transaction_aux.validate_skip_ref(cs, weak) - && t_CurrencyCollection.validate_skip(cs, weak) - && t_HASH_UPDATE_Account.validate_skip_ref(cs, weak) - && t_TransactionDescr.validate_skip_ref(cs, weak); + && t_Transaction_aux.validate_skip_ref(ops, cs, weak) + && t_CurrencyCollection.validate_skip(ops, cs, weak) + && t_HASH_UPDATE_Account.validate_skip_ref(ops, cs, weak) + && t_TransactionDescr.validate_skip_ref(ops, cs, weak); } bool Transaction::unpack(vm::CellSlice& cs, Transaction::Record& data) const { @@ -7496,11 +7501,11 @@ int MERKLE_UPDATE::check_tag(const vm::CellSlice& cs) const { return cs.prefetch_ulong(8) == 2 ? _merkle_update : -1; } -bool MERKLE_UPDATE::validate_skip(vm::CellSlice& cs, bool weak) const { +bool MERKLE_UPDATE::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { return cs.fetch_ulong(8) == 2 && cs.advance(512) - && X_.validate_skip_ref(cs, weak) - && X_.validate_skip_ref(cs, weak); + && X_.validate_skip_ref(ops, cs, weak) + && X_.validate_skip_ref(ops, cs, weak); } bool MERKLE_UPDATE::unpack(vm::CellSlice& cs, MERKLE_UPDATE::Record& data) const { @@ -7552,7 +7557,7 @@ int HASH_UPDATE::check_tag(const vm::CellSlice& cs) const { return cs.prefetch_ulong(8) == 0x72 ? update_hashes : -1; } -bool HASH_UPDATE::validate_skip(vm::CellSlice& cs, bool weak) const { +bool HASH_UPDATE::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { return cs.fetch_ulong(8) == 0x72 && cs.advance(512); } @@ -7627,11 +7632,11 @@ bool AccountBlock::skip(vm::CellSlice& cs) const { && cs.advance_refs(1); } -bool AccountBlock::validate_skip(vm::CellSlice& cs, bool weak) const { +bool AccountBlock::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { return cs.fetch_ulong(4) == 5 && cs.advance(256) - && t_HashmapAug_64_Ref_Transaction_CurrencyCollection.validate_skip(cs, weak) - && t_HASH_UPDATE_Account.validate_skip_ref(cs, weak); + && t_HashmapAug_64_Ref_Transaction_CurrencyCollection.validate_skip(ops, cs, weak) + && t_HASH_UPDATE_Account.validate_skip_ref(ops, cs, weak); } bool AccountBlock::unpack(vm::CellSlice& cs, AccountBlock::Record& data) const { @@ -7709,8 +7714,8 @@ bool ShardAccountBlocks::skip(vm::CellSlice& cs) const { return t_HashmapAugE_256_AccountBlock_CurrencyCollection.skip(cs); } -bool ShardAccountBlocks::validate_skip(vm::CellSlice& cs, bool weak) const { - return t_HashmapAugE_256_AccountBlock_CurrencyCollection.validate_skip(cs, weak); +bool ShardAccountBlocks::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_HashmapAugE_256_AccountBlock_CurrencyCollection.validate_skip(ops, cs, weak); } bool ShardAccountBlocks::unpack(vm::CellSlice& cs, ShardAccountBlocks::Record& data) const { @@ -7774,10 +7779,10 @@ bool TrStoragePhase::skip(vm::CellSlice& cs) const { && t_AccStatusChange.skip(cs); } -bool TrStoragePhase::validate_skip(vm::CellSlice& cs, bool weak) const { - return t_Grams.validate_skip(cs, weak) - && t_Maybe_Grams.validate_skip(cs, weak) - && t_AccStatusChange.validate_skip(cs, weak); +bool TrStoragePhase::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_Grams.validate_skip(ops, cs, weak) + && t_Maybe_Grams.validate_skip(ops, cs, weak) + && t_AccStatusChange.validate_skip(ops, cs, weak); } bool TrStoragePhase::unpack(vm::CellSlice& cs, TrStoragePhase::Record& data) const { @@ -7869,7 +7874,7 @@ bool AccStatusChange::skip(vm::CellSlice& cs) const { return false; } -bool AccStatusChange::validate_skip(vm::CellSlice& cs, bool weak) const { +bool AccStatusChange::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case acst_unchanged: return cs.advance(1); @@ -8035,9 +8040,9 @@ bool TrCreditPhase::skip(vm::CellSlice& cs) const { && t_CurrencyCollection.skip(cs); } -bool TrCreditPhase::validate_skip(vm::CellSlice& cs, bool weak) const { - return t_Maybe_Grams.validate_skip(cs, weak) - && t_CurrencyCollection.validate_skip(cs, weak); +bool TrCreditPhase::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_Maybe_Grams.validate_skip(ops, cs, weak) + && t_CurrencyCollection.validate_skip(ops, cs, weak); } bool TrCreditPhase::unpack(vm::CellSlice& cs, TrCreditPhase::Record& data) const { @@ -8110,12 +8115,12 @@ bool TrComputePhase_aux::skip(vm::CellSlice& cs) const { && cs.advance(544); } -bool TrComputePhase_aux::validate_skip(vm::CellSlice& cs, bool weak) const { - return t_VarUInteger_7.validate_skip(cs, weak) - && t_VarUInteger_7.validate_skip(cs, weak) - && t_Maybe_VarUInteger_3.validate_skip(cs, weak) +bool TrComputePhase_aux::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_VarUInteger_7.validate_skip(ops, cs, weak) + && t_VarUInteger_7.validate_skip(ops, cs, weak) + && t_Maybe_VarUInteger_3.validate_skip(ops, cs, weak) && cs.advance(40) - && t_Maybe_int32.validate_skip(cs, weak) + && t_Maybe_int32.validate_skip(ops, cs, weak) && cs.advance(544); } @@ -8200,15 +8205,15 @@ bool TrComputePhase::skip(vm::CellSlice& cs) const { return false; } -bool TrComputePhase::validate_skip(vm::CellSlice& cs, bool weak) const { +bool TrComputePhase::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case tr_phase_compute_skipped: return cs.advance(1) - && t_ComputeSkipReason.validate_skip(cs, weak); + && t_ComputeSkipReason.validate_skip(ops, cs, weak); case tr_phase_compute_vm: return cs.advance(4) - && t_Grams.validate_skip(cs, weak) - && t_TrComputePhase_aux.validate_skip_ref(cs, weak); + && t_Grams.validate_skip(ops, cs, weak) + && t_TrComputePhase_aux.validate_skip_ref(ops, cs, weak); } return false; } @@ -8327,7 +8332,7 @@ int ComputeSkipReason::check_tag(const vm::CellSlice& cs) const { return -1; } -bool ComputeSkipReason::validate_skip(vm::CellSlice& cs, bool weak) const { +bool ComputeSkipReason::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case cskip_no_state: return cs.advance(2); @@ -8499,15 +8504,15 @@ bool TrActionPhase::skip(vm::CellSlice& cs) const { && t_StorageUsedShort.skip(cs); } -bool TrActionPhase::validate_skip(vm::CellSlice& cs, bool weak) const { +bool TrActionPhase::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { return cs.advance(3) - && t_AccStatusChange.validate_skip(cs, weak) - && t_Maybe_Grams.validate_skip(cs, weak) - && t_Maybe_Grams.validate_skip(cs, weak) + && t_AccStatusChange.validate_skip(ops, cs, weak) + && t_Maybe_Grams.validate_skip(ops, cs, weak) + && t_Maybe_Grams.validate_skip(ops, cs, weak) && cs.advance(32) - && t_Maybe_int32.validate_skip(cs, weak) + && t_Maybe_int32.validate_skip(ops, cs, weak) && cs.advance(320) - && t_StorageUsedShort.validate_skip(cs, weak); + && t_StorageUsedShort.validate_skip(ops, cs, weak); } bool TrActionPhase::unpack(vm::CellSlice& cs, TrActionPhase::Record& data) const { @@ -8616,19 +8621,19 @@ bool TrBouncePhase::skip(vm::CellSlice& cs) const { return false; } -bool TrBouncePhase::validate_skip(vm::CellSlice& cs, bool weak) const { +bool TrBouncePhase::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case tr_phase_bounce_negfunds: return cs.advance(2); case tr_phase_bounce_nofunds: return cs.advance(2) - && t_StorageUsedShort.validate_skip(cs, weak) - && t_Grams.validate_skip(cs, weak); + && t_StorageUsedShort.validate_skip(ops, cs, weak) + && t_Grams.validate_skip(ops, cs, weak); case tr_phase_bounce_ok: return cs.advance(1) - && t_StorageUsedShort.validate_skip(cs, weak) - && t_Grams.validate_skip(cs, weak) - && t_Grams.validate_skip(cs, weak); + && t_StorageUsedShort.validate_skip(ops, cs, weak) + && t_Grams.validate_skip(ops, cs, weak) + && t_Grams.validate_skip(ops, cs, weak); } return false; } @@ -8912,48 +8917,48 @@ bool TransactionDescr::skip(vm::CellSlice& cs) const { return false; } -bool TransactionDescr::validate_skip(vm::CellSlice& cs, bool weak) const { +bool TransactionDescr::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case trans_ord: return cs.advance(5) - && t_Maybe_TrStoragePhase.validate_skip(cs, weak) - && t_Maybe_TrCreditPhase.validate_skip(cs, weak) - && t_TrComputePhase.validate_skip(cs, weak) - && t_Maybe_Ref_TrActionPhase.validate_skip(cs, weak) + && t_Maybe_TrStoragePhase.validate_skip(ops, cs, weak) + && t_Maybe_TrCreditPhase.validate_skip(ops, cs, weak) + && t_TrComputePhase.validate_skip(ops, cs, weak) + && t_Maybe_Ref_TrActionPhase.validate_skip(ops, cs, weak) && cs.advance(1) - && t_Maybe_TrBouncePhase.validate_skip(cs, weak) + && t_Maybe_TrBouncePhase.validate_skip(ops, cs, weak) && cs.advance(1); case trans_storage: return cs.advance(4) - && t_TrStoragePhase.validate_skip(cs, weak); + && t_TrStoragePhase.validate_skip(ops, cs, weak); case trans_tick_tock: return cs.advance(4) - && t_TrStoragePhase.validate_skip(cs, weak) - && t_TrComputePhase.validate_skip(cs, weak) - && t_Maybe_Ref_TrActionPhase.validate_skip(cs, weak) + && t_TrStoragePhase.validate_skip(ops, cs, weak) + && t_TrComputePhase.validate_skip(ops, cs, weak) + && t_Maybe_Ref_TrActionPhase.validate_skip(ops, cs, weak) && cs.advance(2); case trans_split_prepare: return cs.advance(528) - && t_Maybe_TrStoragePhase.validate_skip(cs, weak) - && t_TrComputePhase.validate_skip(cs, weak) - && t_Maybe_Ref_TrActionPhase.validate_skip(cs, weak) + && t_Maybe_TrStoragePhase.validate_skip(ops, cs, weak) + && t_TrComputePhase.validate_skip(ops, cs, weak) + && t_Maybe_Ref_TrActionPhase.validate_skip(ops, cs, weak) && cs.advance(2); case trans_split_install: return cs.advance(528) - && t_Transaction.validate_skip_ref(cs, weak) + && t_Transaction.validate_skip_ref(ops, cs, weak) && cs.advance(1); case trans_merge_prepare: return cs.advance(528) - && t_TrStoragePhase.validate_skip(cs, weak) + && t_TrStoragePhase.validate_skip(ops, cs, weak) && cs.advance(1); case trans_merge_install: return cs.fetch_ulong(4) == 7 && cs.advance(524) - && t_Transaction.validate_skip_ref(cs, weak) - && t_Maybe_TrStoragePhase.validate_skip(cs, weak) - && t_Maybe_TrCreditPhase.validate_skip(cs, weak) - && t_TrComputePhase.validate_skip(cs, weak) - && t_Maybe_Ref_TrActionPhase.validate_skip(cs, weak) + && t_Transaction.validate_skip_ref(ops, cs, weak) + && t_Maybe_TrStoragePhase.validate_skip(ops, cs, weak) + && t_Maybe_TrCreditPhase.validate_skip(ops, cs, weak) + && t_TrComputePhase.validate_skip(ops, cs, weak) + && t_Maybe_Ref_TrActionPhase.validate_skip(ops, cs, weak) && cs.advance(2); } return false; @@ -9342,11 +9347,11 @@ bool SmartContractInfo::skip(vm::CellSlice& cs) const { && t_MsgAddressInt.skip(cs); } -bool SmartContractInfo::validate_skip(vm::CellSlice& cs, bool weak) const { +bool SmartContractInfo::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { return cs.fetch_ulong(32) == 0x76ef1ea && cs.advance(448) - && t_CurrencyCollection.validate_skip(cs, weak) - && t_MsgAddressInt.validate_skip(cs, weak); + && t_CurrencyCollection.validate_skip(ops, cs, weak) + && t_MsgAddressInt.validate_skip(ops, cs, weak); } bool SmartContractInfo::unpack(vm::CellSlice& cs, SmartContractInfo::Record& data) const { @@ -9435,15 +9440,15 @@ bool OutList::skip(vm::CellSlice& cs) const { return false; } -bool OutList::validate_skip(vm::CellSlice& cs, bool weak) const { +bool OutList::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case out_list_empty: return m_ == 0; case out_list: { int n; return add_r1(n, 1, m_) - && OutList{n}.validate_skip_ref(cs, weak) - && t_OutAction.validate_skip(cs, weak); + && OutList{n}.validate_skip_ref(ops, cs, weak) + && t_OutAction.validate_skip(ops, cs, weak); } } return false; @@ -9555,10 +9560,147 @@ bool OutList::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const { } +// +// code for type `LibRef` +// + +int LibRef::check_tag(const vm::CellSlice& cs) const { + switch (get_tag(cs)) { + case libref_hash: + return cs.have(1) ? libref_hash : -1; + case libref_ref: + return cs.have(1) ? libref_ref : -1; + } + return -1; +} + +bool LibRef::skip(vm::CellSlice& cs) const { + switch (get_tag(cs)) { + case libref_hash: + return cs.advance(257); + case libref_ref: + return cs.advance_ext(0x10001); + } + return false; +} + +bool LibRef::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + switch (get_tag(cs)) { + case libref_hash: + return cs.advance(257); + case libref_ref: + return cs.advance_ext(0x10001); + } + return false; +} + +bool LibRef::unpack(vm::CellSlice& cs, LibRef::Record_libref_hash& data) const { + return cs.fetch_ulong(1) == 0 + && cs.fetch_bits_to(data.lib_hash.bits(), 256); +} + +bool LibRef::unpack_libref_hash(vm::CellSlice& cs, td::BitArray<256>& lib_hash) const { + return cs.fetch_ulong(1) == 0 + && cs.fetch_bits_to(lib_hash.bits(), 256); +} + +bool LibRef::cell_unpack(Ref cell_ref, LibRef::Record_libref_hash& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool LibRef::cell_unpack_libref_hash(Ref cell_ref, td::BitArray<256>& lib_hash) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_libref_hash(cs, lib_hash) && cs.empty_ext(); +} + +bool LibRef::unpack(vm::CellSlice& cs, LibRef::Record_libref_ref& data) const { + return cs.fetch_ulong(1) == 1 + && cs.fetch_ref_to(data.library); +} + +bool LibRef::unpack_libref_ref(vm::CellSlice& cs, Ref& library) const { + return cs.fetch_ulong(1) == 1 + && cs.fetch_ref_to(library); +} + +bool LibRef::cell_unpack(Ref cell_ref, LibRef::Record_libref_ref& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool LibRef::cell_unpack_libref_ref(Ref cell_ref, Ref& library) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_libref_ref(cs, library) && cs.empty_ext(); +} + +bool LibRef::pack(vm::CellBuilder& cb, const LibRef::Record_libref_hash& data) const { + return cb.store_long_bool(0, 1) + && cb.store_bits_bool(data.lib_hash.cbits(), 256); +} + +bool LibRef::pack_libref_hash(vm::CellBuilder& cb, td::BitArray<256> lib_hash) const { + return cb.store_long_bool(0, 1) + && cb.store_bits_bool(lib_hash.cbits(), 256); +} + +bool LibRef::cell_pack(Ref& cell_ref, const LibRef::Record_libref_hash& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool LibRef::cell_pack_libref_hash(Ref& cell_ref, td::BitArray<256> lib_hash) const { + vm::CellBuilder cb; + return pack_libref_hash(cb, lib_hash) && std::move(cb).finalize_to(cell_ref); +} + +bool LibRef::pack(vm::CellBuilder& cb, const LibRef::Record_libref_ref& data) const { + return cb.store_long_bool(1, 1) + && cb.store_ref_bool(data.library); +} + +bool LibRef::pack_libref_ref(vm::CellBuilder& cb, Ref library) const { + return cb.store_long_bool(1, 1) + && cb.store_ref_bool(library); +} + +bool LibRef::cell_pack(Ref& cell_ref, const LibRef::Record_libref_ref& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool LibRef::cell_pack_libref_ref(Ref& cell_ref, Ref library) const { + vm::CellBuilder cb; + return pack_libref_ref(cb, std::move(library)) && std::move(cb).finalize_to(cell_ref); +} + +bool LibRef::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const { + switch (get_tag(cs)) { + case libref_hash: + return cs.advance(1) + && pp.open("libref_hash") + && pp.fetch_bits_field(cs, 256, "lib_hash") + && pp.close(); + case libref_ref: + return cs.advance(1) + && pp.open("libref_ref") + && pp.field("library") + && t_Anything.print_ref(pp, cs.fetch_ref()) + && pp.close(); + } + return pp.fail("unknown constructor for LibRef"); +} + +const LibRef t_LibRef; + // // code for type `OutAction` // -constexpr unsigned OutAction::cons_tag[3]; +constexpr unsigned OutAction::cons_tag[4]; int OutAction::check_tag(const vm::CellSlice& cs) const { switch (get_tag(cs)) { @@ -9568,6 +9710,8 @@ int OutAction::check_tag(const vm::CellSlice& cs) const { return cs.prefetch_ulong(32) == 0xad4de08eU ? action_set_code : -1; case action_reserve_currency: return cs.prefetch_ulong(32) == 0x36e6b809 ? action_reserve_currency : -1; + case action_change_library: + return cs.prefetch_ulong(32) == 0x26fa1dd4 ? action_change_library : -1; } return -1; } @@ -9581,23 +9725,37 @@ bool OutAction::skip(vm::CellSlice& cs) const { case action_reserve_currency: return cs.advance(40) && t_CurrencyCollection.skip(cs); + case action_change_library: { + int mode; + return cs.advance(32) + && cs.fetch_uint_to(7, mode) + && mode <= 2 + && t_LibRef.skip(cs); + } } return false; } -bool OutAction::validate_skip(vm::CellSlice& cs, bool weak) const { +bool OutAction::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case action_send_msg: return cs.fetch_ulong(32) == 0xec3c86d && cs.advance(8) - && t_MessageRelaxed_Any.validate_skip_ref(cs, weak); + && t_MessageRelaxed_Any.validate_skip_ref(ops, cs, weak); case action_set_code: return cs.fetch_ulong(32) == 0xad4de08eU && cs.advance_refs(1); case action_reserve_currency: return cs.fetch_ulong(32) == 0x36e6b809 && cs.advance(8) - && t_CurrencyCollection.validate_skip(cs, weak); + && t_CurrencyCollection.validate_skip(ops, cs, weak); + case action_change_library: { + int mode; + return cs.fetch_ulong(32) == 0x26fa1dd4 + && cs.fetch_uint_to(7, mode) + && mode <= 2 + && t_LibRef.validate_skip(ops, cs, weak); + } } return false; } @@ -9672,6 +9830,32 @@ bool OutAction::cell_unpack_action_reserve_currency(Ref cell_ref, int& return unpack_action_reserve_currency(cs, mode, currency) && cs.empty_ext(); } +bool OutAction::unpack(vm::CellSlice& cs, OutAction::Record_action_change_library& data) const { + return cs.fetch_ulong(32) == 0x26fa1dd4 + && cs.fetch_uint_to(7, data.mode) + && data.mode <= 2 + && t_LibRef.fetch_to(cs, data.libref); +} + +bool OutAction::unpack_action_change_library(vm::CellSlice& cs, int& mode, Ref& libref) const { + return cs.fetch_ulong(32) == 0x26fa1dd4 + && cs.fetch_uint_to(7, mode) + && mode <= 2 + && t_LibRef.fetch_to(cs, libref); +} + +bool OutAction::cell_unpack(Ref cell_ref, OutAction::Record_action_change_library& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool OutAction::cell_unpack_action_change_library(Ref cell_ref, int& mode, Ref& libref) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_action_change_library(cs, mode, libref) && cs.empty_ext(); +} + bool OutAction::pack(vm::CellBuilder& cb, const OutAction::Record_action_send_msg& data) const { return cb.store_long_bool(0xec3c86d, 32) && cb.store_ulong_rchk_bool(data.mode, 8) @@ -9736,6 +9920,30 @@ bool OutAction::cell_pack_action_reserve_currency(Ref& cell_ref, int m return pack_action_reserve_currency(cb, mode, std::move(currency)) && std::move(cb).finalize_to(cell_ref); } +bool OutAction::pack(vm::CellBuilder& cb, const OutAction::Record_action_change_library& data) const { + return cb.store_long_bool(0x26fa1dd4, 32) + && cb.store_ulong_rchk_bool(data.mode, 7) + && data.mode <= 2 + && t_LibRef.store_from(cb, data.libref); +} + +bool OutAction::pack_action_change_library(vm::CellBuilder& cb, int mode, Ref libref) const { + return cb.store_long_bool(0x26fa1dd4, 32) + && cb.store_ulong_rchk_bool(mode, 7) + && mode <= 2 + && t_LibRef.store_from(cb, libref); +} + +bool OutAction::cell_pack(Ref& cell_ref, const OutAction::Record_action_change_library& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool OutAction::cell_pack_action_change_library(Ref& cell_ref, int mode, Ref libref) const { + vm::CellBuilder cb; + return pack_action_change_library(cb, mode, std::move(libref)) && std::move(cb).finalize_to(cell_ref); +} + bool OutAction::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const { switch (get_tag(cs)) { case action_send_msg: { @@ -9764,6 +9972,17 @@ bool OutAction::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const { && t_CurrencyCollection.print_skip(pp, cs) && pp.close(); } + case action_change_library: { + int mode; + return cs.fetch_ulong(32) == 0x26fa1dd4 + && pp.open("action_change_library") + && cs.fetch_uint_to(7, mode) + && pp.field_int(mode, "mode") + && mode <= 2 + && pp.field("libref") + && t_LibRef.print_skip(pp, cs) + && pp.close(); + } } return pp.fail("unknown constructor for OutAction"); } @@ -9783,9 +10002,9 @@ bool OutListNode::skip(vm::CellSlice& cs) const { && t_OutAction.skip(cs); } -bool OutListNode::validate_skip(vm::CellSlice& cs, bool weak) const { +bool OutListNode::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { return cs.advance_refs(1) - && t_OutAction.validate_skip(cs, weak); + && t_OutAction.validate_skip(ops, cs, weak); } bool OutListNode::unpack(vm::CellSlice& cs, OutListNode::Record& data) const { @@ -9849,7 +10068,7 @@ int ShardIdent::check_tag(const vm::CellSlice& cs) const { return cs.prefetch_ulong(2) == 0 ? shard_ident : -1; } -bool ShardIdent::validate_skip(vm::CellSlice& cs, bool weak) const { +bool ShardIdent::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { int shard_pfx_bits; return cs.fetch_ulong(2) == 0 && cs.fetch_uint_leq(60, shard_pfx_bits) @@ -9971,8 +10190,8 @@ int BlockIdExt::check_tag(const vm::CellSlice& cs) const { return block_id_ext; } -bool BlockIdExt::validate_skip(vm::CellSlice& cs, bool weak) const { - return t_ShardIdent.validate_skip(cs, weak) +bool BlockIdExt::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_ShardIdent.validate_skip(ops, cs, weak) && cs.advance(544); } @@ -10084,12 +10303,12 @@ bool ShardStateUnsplit_aux::skip(vm::CellSlice& cs) const { && t_Maybe_BlkMasterInfo.skip(cs); } -bool ShardStateUnsplit_aux::validate_skip(vm::CellSlice& cs, bool weak) const { +bool ShardStateUnsplit_aux::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { return cs.advance(128) - && t_CurrencyCollection.validate_skip(cs, weak) - && t_CurrencyCollection.validate_skip(cs, weak) - && t_HashmapE_256_LibDescr.validate_skip(cs, weak) - && t_Maybe_BlkMasterInfo.validate_skip(cs, weak); + && t_CurrencyCollection.validate_skip(ops, cs, weak) + && t_CurrencyCollection.validate_skip(ops, cs, weak) + && t_HashmapE_256_LibDescr.validate_skip(ops, cs, weak) + && t_Maybe_BlkMasterInfo.validate_skip(ops, cs, weak); } bool ShardStateUnsplit_aux::unpack(vm::CellSlice& cs, ShardStateUnsplit_aux::Record& data) const { @@ -10152,16 +10371,16 @@ bool ShardStateUnsplit::skip(vm::CellSlice& cs) const { && t_Maybe_Ref_McStateExtra.skip(cs); } -bool ShardStateUnsplit::validate_skip(vm::CellSlice& cs, bool weak) const { +bool ShardStateUnsplit::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { return cs.fetch_ulong(32) == 0x9023afe2U && cs.advance(32) - && t_ShardIdent.validate_skip(cs, weak) + && t_ShardIdent.validate_skip(ops, cs, weak) && cs.advance(192) - && t_OutMsgQueueInfo.validate_skip_ref(cs, weak) + && t_OutMsgQueueInfo.validate_skip_ref(ops, cs, weak) && cs.advance(1) - && t_ShardAccounts.validate_skip_ref(cs, weak) - && t_ShardStateUnsplit_aux.validate_skip_ref(cs, weak) - && t_Maybe_Ref_McStateExtra.validate_skip(cs, weak); + && t_ShardAccounts.validate_skip_ref(ops, cs, weak) + && t_ShardStateUnsplit_aux.validate_skip_ref(ops, cs, weak) + && t_Maybe_Ref_McStateExtra.validate_skip(ops, cs, weak); } bool ShardStateUnsplit::unpack(vm::CellSlice& cs, ShardStateUnsplit::Record& data) const { @@ -10263,14 +10482,14 @@ bool ShardState::skip(vm::CellSlice& cs) const { return false; } -bool ShardState::validate_skip(vm::CellSlice& cs, bool weak) const { +bool ShardState::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case cons1: - return t_ShardStateUnsplit.validate_skip(cs, weak); + return t_ShardStateUnsplit.validate_skip(ops, cs, weak); case split_state: return cs.fetch_ulong(32) == 0x5f327da5 - && t_ShardStateUnsplit.validate_skip_ref(cs, weak) - && t_ShardStateUnsplit.validate_skip_ref(cs, weak); + && t_ShardStateUnsplit.validate_skip_ref(ops, cs, weak) + && t_ShardStateUnsplit.validate_skip_ref(ops, cs, weak); } return false; } @@ -10393,10 +10612,10 @@ bool LibDescr::skip(vm::CellSlice& cs) const { && t_Hashmap_256_True.skip(cs); } -bool LibDescr::validate_skip(vm::CellSlice& cs, bool weak) const { +bool LibDescr::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { return cs.fetch_ulong(2) == 0 && cs.advance_refs(1) - && t_Hashmap_256_True.validate_skip(cs, weak); + && t_Hashmap_256_True.validate_skip(ops, cs, weak); } bool LibDescr::unpack(vm::CellSlice& cs, LibDescr::Record& data) const { @@ -10484,7 +10703,7 @@ bool BlockInfo::skip(vm::CellSlice& cs) const { && (!vert_seqno_incr || cs.advance_refs(1)); } -bool BlockInfo::validate_skip(vm::CellSlice& cs, bool weak) const { +bool BlockInfo::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { int not_master, after_merge, vert_seqno_incr, seq_no, vert_seq_no, prev_seq_no; return cs.fetch_ulong(32) == 0x9bc7a987U && cs.advance(32) @@ -10497,11 +10716,11 @@ bool BlockInfo::validate_skip(vm::CellSlice& cs, bool weak) const { && cs.fetch_uint_to(32, vert_seq_no) && vert_seqno_incr <= vert_seq_no && add_r1(prev_seq_no, 1, seq_no) - && t_ShardIdent.validate_skip(cs, weak) + && t_ShardIdent.validate_skip(ops, cs, weak) && cs.advance(288) - && (!not_master || t_BlkMasterInfo.validate_skip_ref(cs, weak)) - && BlkPrevInfo{after_merge}.validate_skip_ref(cs, weak) - && (!vert_seqno_incr || t_BlkPrevInfo_0.validate_skip_ref(cs, weak)); + && (!not_master || t_BlkMasterInfo.validate_skip_ref(ops, cs, weak)) + && BlkPrevInfo{after_merge}.validate_skip_ref(ops, cs, weak) + && (!vert_seqno_incr || t_BlkPrevInfo_0.validate_skip_ref(ops, cs, weak)); } bool BlockInfo::unpack(vm::CellSlice& cs, BlockInfo::Record& data) const { @@ -10656,14 +10875,14 @@ bool BlkPrevInfo::skip(vm::CellSlice& cs) const { return false; } -bool BlkPrevInfo::validate_skip(vm::CellSlice& cs, bool weak) const { +bool BlkPrevInfo::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case prev_blk_info: return cs.advance(608) && m_ == 0; case prev_blks_info: - return t_ExtBlkRef.validate_skip_ref(cs, weak) - && t_ExtBlkRef.validate_skip_ref(cs, weak) + return t_ExtBlkRef.validate_skip_ref(ops, cs, weak) + && t_ExtBlkRef.validate_skip_ref(ops, cs, weak) && m_ == 1; } return false; @@ -10787,13 +11006,13 @@ int Block::check_tag(const vm::CellSlice& cs) const { return cs.prefetch_ulong(32) == 0x11ef55aa ? block : -1; } -bool Block::validate_skip(vm::CellSlice& cs, bool weak) const { +bool Block::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { return cs.fetch_ulong(32) == 0x11ef55aa && cs.advance(32) - && t_BlockInfo.validate_skip_ref(cs, weak) - && t_ValueFlow.validate_skip_ref(cs, weak) - && t_MERKLE_UPDATE_ShardState.validate_skip_ref(cs, weak) - && t_BlockExtra.validate_skip_ref(cs, weak); + && t_BlockInfo.validate_skip_ref(ops, cs, weak) + && t_ValueFlow.validate_skip_ref(ops, cs, weak) + && t_MERKLE_UPDATE_ShardState.validate_skip_ref(ops, cs, weak) + && t_BlockExtra.validate_skip_ref(ops, cs, weak); } bool Block::unpack(vm::CellSlice& cs, Block::Record& data) const { @@ -10856,13 +11075,13 @@ bool BlockExtra::skip(vm::CellSlice& cs) const { && t_Maybe_Ref_McBlockExtra.skip(cs); } -bool BlockExtra::validate_skip(vm::CellSlice& cs, bool weak) const { +bool BlockExtra::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { return cs.fetch_ulong(32) == 0x4a33f6fd - && t_InMsgDescr.validate_skip_ref(cs, weak) - && t_OutMsgDescr.validate_skip_ref(cs, weak) - && t_ShardAccountBlocks.validate_skip_ref(cs, weak) + && t_InMsgDescr.validate_skip_ref(ops, cs, weak) + && t_OutMsgDescr.validate_skip_ref(ops, cs, weak) + && t_ShardAccountBlocks.validate_skip_ref(ops, cs, weak) && cs.advance(512) - && t_Maybe_Ref_McBlockExtra.validate_skip(cs, weak); + && t_Maybe_Ref_McBlockExtra.validate_skip(ops, cs, weak); } bool BlockExtra::unpack(vm::CellSlice& cs, BlockExtra::Record& data) const { @@ -10929,11 +11148,11 @@ bool ValueFlow_aux::skip(vm::CellSlice& cs) const { && t_CurrencyCollection.skip(cs); } -bool ValueFlow_aux::validate_skip(vm::CellSlice& cs, bool weak) const { - return t_CurrencyCollection.validate_skip(cs, weak) - && t_CurrencyCollection.validate_skip(cs, weak) - && t_CurrencyCollection.validate_skip(cs, weak) - && t_CurrencyCollection.validate_skip(cs, weak); +bool ValueFlow_aux::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_CurrencyCollection.validate_skip(ops, cs, weak) + && t_CurrencyCollection.validate_skip(ops, cs, weak) + && t_CurrencyCollection.validate_skip(ops, cs, weak) + && t_CurrencyCollection.validate_skip(ops, cs, weak); } bool ValueFlow_aux::unpack(vm::CellSlice& cs, ValueFlow_aux::Record& data) const { @@ -10991,11 +11210,11 @@ bool ValueFlow_aux1::skip(vm::CellSlice& cs) const { && t_CurrencyCollection.skip(cs); } -bool ValueFlow_aux1::validate_skip(vm::CellSlice& cs, bool weak) const { - return t_CurrencyCollection.validate_skip(cs, weak) - && t_CurrencyCollection.validate_skip(cs, weak) - && t_CurrencyCollection.validate_skip(cs, weak) - && t_CurrencyCollection.validate_skip(cs, weak); +bool ValueFlow_aux1::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_CurrencyCollection.validate_skip(ops, cs, weak) + && t_CurrencyCollection.validate_skip(ops, cs, weak) + && t_CurrencyCollection.validate_skip(ops, cs, weak) + && t_CurrencyCollection.validate_skip(ops, cs, weak); } bool ValueFlow_aux1::unpack(vm::CellSlice& cs, ValueFlow_aux1::Record& data) const { @@ -11053,11 +11272,11 @@ bool ValueFlow::skip(vm::CellSlice& cs) const { && cs.advance_refs(1); } -bool ValueFlow::validate_skip(vm::CellSlice& cs, bool weak) const { +bool ValueFlow::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { return cs.fetch_ulong(32) == 0xb8e48dfbU - && t_ValueFlow_aux.validate_skip_ref(cs, weak) - && t_CurrencyCollection.validate_skip(cs, weak) - && t_ValueFlow_aux1.validate_skip_ref(cs, weak); + && t_ValueFlow_aux.validate_skip_ref(ops, cs, weak) + && t_CurrencyCollection.validate_skip(ops, cs, weak) + && t_ValueFlow_aux1.validate_skip_ref(ops, cs, weak); } bool ValueFlow::unpack(vm::CellSlice& cs, ValueFlow::Record& data) const { @@ -11127,15 +11346,15 @@ bool BinTree::skip(vm::CellSlice& cs) const { return false; } -bool BinTree::validate_skip(vm::CellSlice& cs, bool weak) const { +bool BinTree::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case bt_leaf: return cs.advance(1) - && X_.validate_skip(cs, weak); + && X_.validate_skip(ops, cs, weak); case bt_fork: return cs.advance(1) - && validate_skip_ref(cs, weak) - && validate_skip_ref(cs, weak); + && validate_skip_ref(ops, cs, weak) + && validate_skip_ref(ops, cs, weak); } return false; } @@ -11279,7 +11498,7 @@ bool FutureSplitMerge::skip(vm::CellSlice& cs) const { return false; } -bool FutureSplitMerge::validate_skip(vm::CellSlice& cs, bool weak) const { +bool FutureSplitMerge::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case fsm_none: return cs.advance(1); @@ -11464,16 +11683,16 @@ bool ShardDescr::skip(vm::CellSlice& cs) const { && t_CurrencyCollection.skip(cs); } -bool ShardDescr::validate_skip(vm::CellSlice& cs, bool weak) const { +bool ShardDescr::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { int flags; return cs.fetch_ulong(4) == 11 && cs.advance(709) && cs.fetch_uint_to(3, flags) && flags == 0 && cs.advance(160) - && t_FutureSplitMerge.validate_skip(cs, weak) - && t_CurrencyCollection.validate_skip(cs, weak) - && t_CurrencyCollection.validate_skip(cs, weak); + && t_FutureSplitMerge.validate_skip(ops, cs, weak) + && t_CurrencyCollection.validate_skip(ops, cs, weak) + && t_CurrencyCollection.validate_skip(ops, cs, weak); } bool ShardDescr::unpack(vm::CellSlice& cs, ShardDescr::Record& data) const { @@ -11580,8 +11799,8 @@ bool ShardHashes::skip(vm::CellSlice& cs) const { return t_HashmapE_32_Ref_BinTree_ShardDescr.skip(cs); } -bool ShardHashes::validate_skip(vm::CellSlice& cs, bool weak) const { - return t_HashmapE_32_Ref_BinTree_ShardDescr.validate_skip(cs, weak); +bool ShardHashes::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_HashmapE_32_Ref_BinTree_ShardDescr.validate_skip(ops, cs, weak); } bool ShardHashes::unpack(vm::CellSlice& cs, ShardHashes::Record& data) const { @@ -11658,17 +11877,17 @@ bool BinTreeAug::skip(vm::CellSlice& cs) const { return false; } -bool BinTreeAug::validate_skip(vm::CellSlice& cs, bool weak) const { +bool BinTreeAug::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case bta_leaf: return cs.advance(1) - && Y_.validate_skip(cs, weak) - && X_.validate_skip(cs, weak); + && Y_.validate_skip(ops, cs, weak) + && X_.validate_skip(ops, cs, weak); case bta_fork: return cs.advance(1) - && validate_skip_ref(cs, weak) - && validate_skip_ref(cs, weak) - && Y_.validate_skip(cs, weak); + && validate_skip_ref(ops, cs, weak) + && validate_skip_ref(ops, cs, weak) + && Y_.validate_skip(ops, cs, weak); } return false; } @@ -11807,9 +12026,9 @@ bool ShardFeeCreated::skip(vm::CellSlice& cs) const { && t_CurrencyCollection.skip(cs); } -bool ShardFeeCreated::validate_skip(vm::CellSlice& cs, bool weak) const { - return t_CurrencyCollection.validate_skip(cs, weak) - && t_CurrencyCollection.validate_skip(cs, weak); +bool ShardFeeCreated::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_CurrencyCollection.validate_skip(ops, cs, weak) + && t_CurrencyCollection.validate_skip(ops, cs, weak); } bool ShardFeeCreated::unpack(vm::CellSlice& cs, ShardFeeCreated::Record& data) const { @@ -11877,8 +12096,8 @@ bool ShardFees::skip(vm::CellSlice& cs) const { return t_HashmapAugE_96_ShardFeeCreated_ShardFeeCreated.skip(cs); } -bool ShardFees::validate_skip(vm::CellSlice& cs, bool weak) const { - return t_HashmapAugE_96_ShardFeeCreated_ShardFeeCreated.validate_skip(cs, weak); +bool ShardFees::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_HashmapAugE_96_ShardFeeCreated_ShardFeeCreated.validate_skip(ops, cs, weak); } bool ShardFees::unpack(vm::CellSlice& cs, ShardFees::Record& data) const { @@ -11936,9 +12155,9 @@ int ConfigParams::check_tag(const vm::CellSlice& cs) const { return cons1; } -bool ConfigParams::validate_skip(vm::CellSlice& cs, bool weak) const { +bool ConfigParams::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { return cs.advance(256) - && t_Hashmap_32_Ref_Cell.validate_skip_ref(cs, weak); + && t_Hashmap_32_Ref_Cell.validate_skip_ref(ops, cs, weak); } bool ConfigParams::unpack(vm::CellSlice& cs, ConfigParams::Record& data) const { @@ -12247,8 +12466,8 @@ bool OldMcBlocksInfo::skip(vm::CellSlice& cs) const { return t_HashmapAugE_32_KeyExtBlkRef_KeyMaxLt.skip(cs); } -bool OldMcBlocksInfo::validate_skip(vm::CellSlice& cs, bool weak) const { - return t_HashmapAugE_32_KeyExtBlkRef_KeyMaxLt.validate_skip(cs, weak); +bool OldMcBlocksInfo::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_HashmapAugE_32_KeyExtBlkRef_KeyMaxLt.validate_skip(ops, cs, weak); } bool OldMcBlocksInfo::unpack(vm::CellSlice& cs, OldMcBlocksInfo::Record& data) const { @@ -12351,7 +12570,7 @@ int CreatorStats::check_tag(const vm::CellSlice& cs) const { return cs.prefetch_ulong(4) == 4 ? creator_info : -1; } -bool CreatorStats::validate_skip(vm::CellSlice& cs, bool weak) const { +bool CreatorStats::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { return cs.fetch_ulong(4) == 4 && cs.advance(448); } @@ -12417,23 +12636,43 @@ const CreatorStats t_CreatorStats; // // code for type `BlockCreateStats` // -constexpr unsigned char BlockCreateStats::cons_tag[1]; +constexpr unsigned char BlockCreateStats::cons_tag[2]; int BlockCreateStats::check_tag(const vm::CellSlice& cs) const { - return cs.prefetch_ulong(8) == 23 ? block_create_stats : -1; + switch (get_tag(cs)) { + case block_create_stats: + return cs.prefetch_ulong(8) == 23 ? block_create_stats : -1; + case block_create_stats_ext: + return cs.prefetch_ulong(8) == 0x34 ? block_create_stats_ext : -1; + } + return -1; } bool BlockCreateStats::skip(vm::CellSlice& cs) const { - return cs.advance(8) - && t_HashmapE_256_CreatorStats.skip(cs); + switch (get_tag(cs)) { + case block_create_stats: + return cs.advance(8) + && t_HashmapE_256_CreatorStats.skip(cs); + case block_create_stats_ext: + return cs.advance(8) + && t_HashmapAugE_256_CreatorStats_uint32.skip(cs); + } + return false; } -bool BlockCreateStats::validate_skip(vm::CellSlice& cs, bool weak) const { - return cs.fetch_ulong(8) == 23 - && t_HashmapE_256_CreatorStats.validate_skip(cs, weak); +bool BlockCreateStats::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + switch (get_tag(cs)) { + case block_create_stats: + return cs.fetch_ulong(8) == 23 + && t_HashmapE_256_CreatorStats.validate_skip(ops, cs, weak); + case block_create_stats_ext: + return cs.fetch_ulong(8) == 0x34 + && t_HashmapAugE_256_CreatorStats_uint32.validate_skip(ops, cs, weak); + } + return false; } -bool BlockCreateStats::unpack(vm::CellSlice& cs, BlockCreateStats::Record& data) const { +bool BlockCreateStats::unpack(vm::CellSlice& cs, BlockCreateStats::Record_block_create_stats& data) const { return cs.fetch_ulong(8) == 23 && t_HashmapE_256_CreatorStats.fetch_to(cs, data.counters); } @@ -12443,7 +12682,7 @@ bool BlockCreateStats::unpack_block_create_stats(vm::CellSlice& cs, Ref cell_ref, BlockCreateStats::Record& data) const { +bool BlockCreateStats::cell_unpack(Ref cell_ref, BlockCreateStats::Record_block_create_stats& data) const { if (cell_ref.is_null()) { return false; } auto cs = load_cell_slice(std::move(cell_ref)); return unpack(cs, data) && cs.empty_ext(); @@ -12455,7 +12694,29 @@ bool BlockCreateStats::cell_unpack_block_create_stats(Ref cell_ref, Re return unpack_block_create_stats(cs, counters) && cs.empty_ext(); } -bool BlockCreateStats::pack(vm::CellBuilder& cb, const BlockCreateStats::Record& data) const { +bool BlockCreateStats::unpack(vm::CellSlice& cs, BlockCreateStats::Record_block_create_stats_ext& data) const { + return cs.fetch_ulong(8) == 0x34 + && t_HashmapAugE_256_CreatorStats_uint32.fetch_to(cs, data.counters); +} + +bool BlockCreateStats::unpack_block_create_stats_ext(vm::CellSlice& cs, Ref& counters) const { + return cs.fetch_ulong(8) == 0x34 + && t_HashmapAugE_256_CreatorStats_uint32.fetch_to(cs, counters); +} + +bool BlockCreateStats::cell_unpack(Ref cell_ref, BlockCreateStats::Record_block_create_stats_ext& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool BlockCreateStats::cell_unpack_block_create_stats_ext(Ref cell_ref, Ref& counters) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_block_create_stats_ext(cs, counters) && cs.empty_ext(); +} + +bool BlockCreateStats::pack(vm::CellBuilder& cb, const BlockCreateStats::Record_block_create_stats& data) const { return cb.store_long_bool(23, 8) && t_HashmapE_256_CreatorStats.store_from(cb, data.counters); } @@ -12465,7 +12726,7 @@ bool BlockCreateStats::pack_block_create_stats(vm::CellBuilder& cb, Ref& cell_ref, const BlockCreateStats::Record& data) const { +bool BlockCreateStats::cell_pack(Ref& cell_ref, const BlockCreateStats::Record_block_create_stats& data) const { vm::CellBuilder cb; return pack(cb, data) && std::move(cb).finalize_to(cell_ref); } @@ -12475,12 +12736,42 @@ bool BlockCreateStats::cell_pack_block_create_stats(Ref& cell_ref, Ref return pack_block_create_stats(cb, std::move(counters)) && std::move(cb).finalize_to(cell_ref); } +bool BlockCreateStats::pack(vm::CellBuilder& cb, const BlockCreateStats::Record_block_create_stats_ext& data) const { + return cb.store_long_bool(0x34, 8) + && t_HashmapAugE_256_CreatorStats_uint32.store_from(cb, data.counters); +} + +bool BlockCreateStats::pack_block_create_stats_ext(vm::CellBuilder& cb, Ref counters) const { + return cb.store_long_bool(0x34, 8) + && t_HashmapAugE_256_CreatorStats_uint32.store_from(cb, counters); +} + +bool BlockCreateStats::cell_pack(Ref& cell_ref, const BlockCreateStats::Record_block_create_stats_ext& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool BlockCreateStats::cell_pack_block_create_stats_ext(Ref& cell_ref, Ref counters) const { + vm::CellBuilder cb; + return pack_block_create_stats_ext(cb, std::move(counters)) && std::move(cb).finalize_to(cell_ref); +} + bool BlockCreateStats::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const { - return cs.fetch_ulong(8) == 23 - && pp.open("block_create_stats") - && pp.field("counters") - && t_HashmapE_256_CreatorStats.print_skip(pp, cs) - && pp.close(); + switch (get_tag(cs)) { + case block_create_stats: + return cs.fetch_ulong(8) == 23 + && pp.open("block_create_stats") + && pp.field("counters") + && t_HashmapE_256_CreatorStats.print_skip(pp, cs) + && pp.close(); + case block_create_stats_ext: + return cs.fetch_ulong(8) == 0x34 + && pp.open("block_create_stats_ext") + && pp.field("counters") + && t_HashmapAugE_256_CreatorStats_uint32.print_skip(pp, cs) + && pp.close(); + } + return pp.fail("unknown constructor for BlockCreateStats"); } const BlockCreateStats t_BlockCreateStats; @@ -12504,15 +12795,15 @@ bool McStateExtra_aux::skip(vm::CellSlice& cs) const { && (!(flags & 1) || t_BlockCreateStats.skip(cs)); } -bool McStateExtra_aux::validate_skip(vm::CellSlice& cs, bool weak) const { +bool McStateExtra_aux::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { int flags; return cs.fetch_uint_to(16, flags) && flags <= 1 && cs.advance(65) - && t_OldMcBlocksInfo.validate_skip(cs, weak) + && t_OldMcBlocksInfo.validate_skip(ops, cs, weak) && cs.advance(1) - && t_Maybe_ExtBlkRef.validate_skip(cs, weak) - && (!(flags & 1) || t_BlockCreateStats.validate_skip(cs, weak)); + && t_Maybe_ExtBlkRef.validate_skip(ops, cs, weak) + && (!(flags & 1) || t_BlockCreateStats.validate_skip(ops, cs, weak)); } bool McStateExtra_aux::unpack(vm::CellSlice& cs, McStateExtra_aux::Record& data) const { @@ -12581,12 +12872,12 @@ bool McStateExtra::skip(vm::CellSlice& cs) const { && t_CurrencyCollection.skip(cs); } -bool McStateExtra::validate_skip(vm::CellSlice& cs, bool weak) const { +bool McStateExtra::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { return cs.fetch_ulong(16) == 0xcc26 - && t_ShardHashes.validate_skip(cs, weak) - && t_ConfigParams.validate_skip(cs, weak) - && t_McStateExtra_aux.validate_skip_ref(cs, weak) - && t_CurrencyCollection.validate_skip(cs, weak); + && t_ShardHashes.validate_skip(ops, cs, weak) + && t_ConfigParams.validate_skip(ops, cs, weak) + && t_McStateExtra_aux.validate_skip_ref(ops, cs, weak) + && t_CurrencyCollection.validate_skip(ops, cs, weak); } bool McStateExtra::unpack(vm::CellSlice& cs, McStateExtra::Record& data) const { @@ -12643,7 +12934,7 @@ int SigPubKey::check_tag(const vm::CellSlice& cs) const { return cs.prefetch_ulong(32) == 0x8e81278aU ? ed25519_pubkey : -1; } -bool SigPubKey::validate_skip(vm::CellSlice& cs, bool weak) const { +bool SigPubKey::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { return cs.fetch_ulong(32) == 0x8e81278aU && cs.advance(256); } @@ -12708,7 +12999,7 @@ int CryptoSignatureSimple::check_tag(const vm::CellSlice& cs) const { return cs.prefetch_ulong(4) == 5 ? ed25519_signature : -1; } -bool CryptoSignatureSimple::validate_skip(vm::CellSlice& cs, bool weak) const { +bool CryptoSignatureSimple::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { return cs.fetch_ulong(4) == 5 && cs.advance(512); } @@ -12782,9 +13073,9 @@ bool CryptoSignaturePair::skip(vm::CellSlice& cs) const { && t_CryptoSignature.skip(cs); } -bool CryptoSignaturePair::validate_skip(vm::CellSlice& cs, bool weak) const { +bool CryptoSignaturePair::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { return cs.advance(256) - && t_CryptoSignature.validate_skip(cs, weak); + && t_CryptoSignature.validate_skip(ops, cs, weak); } bool CryptoSignaturePair::unpack(vm::CellSlice& cs, CryptoSignaturePair::Record& data) const { @@ -12848,9 +13139,9 @@ int Certificate::check_tag(const vm::CellSlice& cs) const { return cs.prefetch_ulong(4) == 4 ? certificate : -1; } -bool Certificate::validate_skip(vm::CellSlice& cs, bool weak) const { +bool Certificate::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { return cs.fetch_ulong(4) == 4 - && t_SigPubKey.validate_skip(cs, weak) + && t_SigPubKey.validate_skip(ops, cs, weak) && cs.advance(64); } @@ -12925,9 +13216,9 @@ int CertificateEnv::check_tag(const vm::CellSlice& cs) const { return cs.prefetch_ulong(28) == 0xa419b7d ? certificate_env : -1; } -bool CertificateEnv::validate_skip(vm::CellSlice& cs, bool weak) const { +bool CertificateEnv::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { return cs.fetch_ulong(28) == 0xa419b7d - && t_Certificate.validate_skip(cs, weak); + && t_Certificate.validate_skip(ops, cs, weak); } bool CertificateEnv::unpack(vm::CellSlice& cs, CertificateEnv::Record& data) const { @@ -12995,9 +13286,9 @@ bool SignedCertificate::skip(vm::CellSlice& cs) const { && t_CryptoSignature.skip(cs); } -bool SignedCertificate::validate_skip(vm::CellSlice& cs, bool weak) const { - return t_Certificate.validate_skip(cs, weak) - && t_CryptoSignature.validate_skip(cs, weak); +bool SignedCertificate::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_Certificate.validate_skip(ops, cs, weak) + && t_CryptoSignature.validate_skip(ops, cs, weak); } bool SignedCertificate::unpack(vm::CellSlice& cs, SignedCertificate::Record& data) const { @@ -13079,14 +13370,14 @@ bool CryptoSignature::skip(vm::CellSlice& cs) const { return false; } -bool CryptoSignature::validate_skip(vm::CellSlice& cs, bool weak) const { +bool CryptoSignature::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case cons1: - return t_CryptoSignatureSimple.validate_skip(cs, weak); + return t_CryptoSignatureSimple.validate_skip(ops, cs, weak); case chained_signature: return cs.fetch_ulong(4) == 15 - && t_SignedCertificate.validate_skip_ref(cs, weak) - && t_CryptoSignatureSimple.validate_skip(cs, weak); + && t_SignedCertificate.validate_skip_ref(ops, cs, weak) + && t_CryptoSignatureSimple.validate_skip(ops, cs, weak); } return false; } @@ -13210,10 +13501,10 @@ bool McBlockExtra_aux::skip(vm::CellSlice& cs) const { && t_Maybe_Ref_InMsg.skip(cs); } -bool McBlockExtra_aux::validate_skip(vm::CellSlice& cs, bool weak) const { - return t_HashmapE_16_CryptoSignaturePair.validate_skip(cs, weak) - && t_Maybe_Ref_InMsg.validate_skip(cs, weak) - && t_Maybe_Ref_InMsg.validate_skip(cs, weak); +bool McBlockExtra_aux::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_HashmapE_16_CryptoSignaturePair.validate_skip(ops, cs, weak) + && t_Maybe_Ref_InMsg.validate_skip(ops, cs, weak) + && t_Maybe_Ref_InMsg.validate_skip(ops, cs, weak); } bool McBlockExtra_aux::unpack(vm::CellSlice& cs, McBlockExtra_aux::Record& data) const { @@ -13294,14 +13585,14 @@ bool McBlockExtra::skip(vm::CellSlice& cs) const { && (!key_block || t_ConfigParams.skip(cs)); } -bool McBlockExtra::validate_skip(vm::CellSlice& cs, bool weak) const { +bool McBlockExtra::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { int key_block; return cs.fetch_ulong(16) == 0xcca5 && cs.fetch_bool_to(key_block) - && t_ShardHashes.validate_skip(cs, weak) - && t_ShardFees.validate_skip(cs, weak) - && t_McBlockExtra_aux.validate_skip_ref(cs, weak) - && (!key_block || t_ConfigParams.validate_skip(cs, weak)); + && t_ShardHashes.validate_skip(ops, cs, weak) + && t_ShardFees.validate_skip(ops, cs, weak) + && t_McBlockExtra_aux.validate_skip_ref(ops, cs, weak) + && (!key_block || t_ConfigParams.validate_skip(ops, cs, weak)); } bool McBlockExtra::unpack(vm::CellSlice& cs, McBlockExtra::Record& data) const { @@ -13378,15 +13669,15 @@ bool ValidatorDescr::skip(vm::CellSlice& cs) const { return false; } -bool ValidatorDescr::validate_skip(vm::CellSlice& cs, bool weak) const { +bool ValidatorDescr::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case validator: return cs.fetch_ulong(8) == 0x53 - && t_SigPubKey.validate_skip(cs, weak) + && t_SigPubKey.validate_skip(ops, cs, weak) && cs.advance(64); case validator_addr: return cs.fetch_ulong(8) == 0x73 - && t_SigPubKey.validate_skip(cs, weak) + && t_SigPubKey.validate_skip(ops, cs, weak) && cs.advance(320); } return false; @@ -13560,7 +13851,7 @@ bool ValidatorSet::skip(vm::CellSlice& cs) const { return false; } -bool ValidatorSet::validate_skip(vm::CellSlice& cs, bool weak) const { +bool ValidatorSet::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case validators: { int total, main; @@ -13570,7 +13861,7 @@ bool ValidatorSet::validate_skip(vm::CellSlice& cs, bool weak) const { && cs.fetch_uint_to(16, main) && main <= total && 1 <= main - && t_Hashmap_16_ValidatorDescr.validate_skip(cs, weak); + && t_Hashmap_16_ValidatorDescr.validate_skip(ops, cs, weak); } case validators_ext: { int total, main; @@ -13581,7 +13872,7 @@ bool ValidatorSet::validate_skip(vm::CellSlice& cs, bool weak) const { && main <= total && 1 <= main && cs.advance(64) - && t_HashmapE_16_ValidatorDescr.validate_skip(cs, weak); + && t_HashmapE_16_ValidatorDescr.validate_skip(ops, cs, weak); } } return false; @@ -13705,7 +13996,7 @@ int GlobalVersion::check_tag(const vm::CellSlice& cs) const { return cs.prefetch_ulong(8) == 0xc4 ? capabilities : -1; } -bool GlobalVersion::validate_skip(vm::CellSlice& cs, bool weak) const { +bool GlobalVersion::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { return cs.fetch_ulong(8) == 0xc4 && cs.advance(96); } @@ -13803,7 +14094,7 @@ bool WorkchainFormat::skip(vm::CellSlice& cs) const { return false; } -bool WorkchainFormat::validate_skip(vm::CellSlice& cs, bool weak) const { +bool WorkchainFormat::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case wfmt_basic: return cs.fetch_ulong(4) == 1 @@ -13974,7 +14265,7 @@ bool WorkchainDescr::skip(vm::CellSlice& cs) const { && WorkchainFormat{basic}.skip(cs); } -bool WorkchainDescr::validate_skip(vm::CellSlice& cs, bool weak) const { +bool WorkchainDescr::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { int actual_min_split, min_split, basic, flags; return cs.fetch_ulong(8) == 0xa6 && cs.advance(32) @@ -13987,7 +14278,7 @@ bool WorkchainDescr::validate_skip(vm::CellSlice& cs, bool weak) const { && cs.fetch_uint_to(13, flags) && flags == 0 && cs.advance(544) - && WorkchainFormat{basic}.validate_skip(cs, weak); + && WorkchainFormat{basic}.validate_skip(ops, cs, weak); } bool WorkchainDescr::unpack(vm::CellSlice& cs, WorkchainDescr::Record& data) const { @@ -14081,10 +14372,10 @@ bool BlockCreateFees::skip(vm::CellSlice& cs) const { && t_Grams.skip(cs); } -bool BlockCreateFees::validate_skip(vm::CellSlice& cs, bool weak) const { +bool BlockCreateFees::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { return cs.fetch_ulong(8) == 0x6b - && t_Grams.validate_skip(cs, weak) - && t_Grams.validate_skip(cs, weak); + && t_Grams.validate_skip(ops, cs, weak) + && t_Grams.validate_skip(ops, cs, weak); } bool BlockCreateFees::unpack(vm::CellSlice& cs, BlockCreateFees::Record& data) const { @@ -14154,7 +14445,7 @@ int StoragePrices::check_tag(const vm::CellSlice& cs) const { return cs.prefetch_ulong(8) == 0xcc ? cons1 : -1; } -bool StoragePrices::validate_skip(vm::CellSlice& cs, bool weak) const { +bool StoragePrices::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { return cs.fetch_ulong(8) == 0xcc && cs.advance(288); } @@ -14242,7 +14533,7 @@ bool GasLimitsPrices::skip(vm::CellSlice& cs) const { return false; } -bool GasLimitsPrices::validate_skip(vm::CellSlice& cs, bool weak) const { +bool GasLimitsPrices::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case gas_prices: return cs.fetch_ulong(8) == 0xdd @@ -14253,7 +14544,7 @@ bool GasLimitsPrices::validate_skip(vm::CellSlice& cs, bool weak) const { case gas_flat_pfx: return cs.fetch_ulong(8) == 0xd1 && cs.advance(128) - && validate_skip(cs, weak); + && validate_skip(ops, cs, weak); } return false; } @@ -14418,7 +14709,7 @@ int ParamLimits::check_tag(const vm::CellSlice& cs) const { return cs.prefetch_ulong(8) == 0xc3 ? param_limits : -1; } -bool ParamLimits::validate_skip(vm::CellSlice& cs, bool weak) const { +bool ParamLimits::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { int underload, soft_limit, hard_limit; return cs.fetch_ulong(8) == 0xc3 && cs.fetch_uint_to(32, underload) @@ -14512,11 +14803,11 @@ int BlockLimits::check_tag(const vm::CellSlice& cs) const { return cs.prefetch_ulong(8) == 0x5d ? block_limits : -1; } -bool BlockLimits::validate_skip(vm::CellSlice& cs, bool weak) const { +bool BlockLimits::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { return cs.fetch_ulong(8) == 0x5d - && t_ParamLimits.validate_skip(cs, weak) - && t_ParamLimits.validate_skip(cs, weak) - && t_ParamLimits.validate_skip(cs, weak); + && t_ParamLimits.validate_skip(ops, cs, weak) + && t_ParamLimits.validate_skip(ops, cs, weak) + && t_ParamLimits.validate_skip(ops, cs, weak); } bool BlockLimits::unpack(vm::CellSlice& cs, BlockLimits::Record& data) const { @@ -14592,7 +14883,7 @@ int MsgForwardPrices::check_tag(const vm::CellSlice& cs) const { return cs.prefetch_ulong(8) == 0xea ? msg_forward_prices : -1; } -bool MsgForwardPrices::validate_skip(vm::CellSlice& cs, bool weak) const { +bool MsgForwardPrices::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { return cs.fetch_ulong(8) == 0xea && cs.advance(256); } @@ -14651,7 +14942,7 @@ int CatchainConfig::check_tag(const vm::CellSlice& cs) const { return cs.prefetch_ulong(8) == 0xc1 ? catchain_config : -1; } -bool CatchainConfig::validate_skip(vm::CellSlice& cs, bool weak) const { +bool CatchainConfig::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { return cs.fetch_ulong(8) == 0xc1 && cs.advance(128); } @@ -14704,7 +14995,7 @@ int ConsensusConfig::check_tag(const vm::CellSlice& cs) const { return cs.prefetch_ulong(8) == 0xd6 ? consensus_config : -1; } -bool ConsensusConfig::validate_skip(vm::CellSlice& cs, bool weak) const { +bool ConsensusConfig::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { int round_candidates; return cs.fetch_ulong(8) == 0xd6 && cs.fetch_uint_to(32, round_candidates) @@ -14777,10 +15068,10 @@ int ValidatorTempKey::check_tag(const vm::CellSlice& cs) const { return cs.prefetch_ulong(4) == 3 ? validator_temp_key : -1; } -bool ValidatorTempKey::validate_skip(vm::CellSlice& cs, bool weak) const { +bool ValidatorTempKey::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { return cs.fetch_ulong(4) == 3 && cs.advance(256) - && t_SigPubKey.validate_skip(cs, weak) + && t_SigPubKey.validate_skip(ops, cs, weak) && cs.advance(64); } @@ -14840,10 +15131,10 @@ bool ValidatorSignedTempKey::skip(vm::CellSlice& cs) const { && t_CryptoSignature.skip(cs); } -bool ValidatorSignedTempKey::validate_skip(vm::CellSlice& cs, bool weak) const { +bool ValidatorSignedTempKey::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { return cs.fetch_ulong(4) == 4 - && t_ValidatorTempKey.validate_skip_ref(cs, weak) - && t_CryptoSignature.validate_skip(cs, weak); + && t_ValidatorTempKey.validate_skip_ref(ops, cs, weak) + && t_CryptoSignature.validate_skip(ops, cs, weak); } bool ValidatorSignedTempKey::unpack(vm::CellSlice& cs, ValidatorSignedTempKey::Record& data) const { @@ -15155,7 +15446,7 @@ bool ConfigParam::skip(vm::CellSlice& cs) const { return false; } -bool ConfigParam::validate_skip(vm::CellSlice& cs, bool weak) const { +bool ConfigParam::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case cons0: return cs.advance(256) @@ -15173,23 +15464,23 @@ bool ConfigParam::validate_skip(vm::CellSlice& cs, bool weak) const { return cs.advance(256) && m_ == 4; case cons6: - return t_Grams.validate_skip(cs, weak) - && t_Grams.validate_skip(cs, weak) + return t_Grams.validate_skip(ops, cs, weak) + && t_Grams.validate_skip(ops, cs, weak) && m_ == 6; case cons7: - return t_ExtraCurrencyCollection.validate_skip(cs, weak) + return t_ExtraCurrencyCollection.validate_skip(ops, cs, weak) && m_ == 7; case cons8: - return t_GlobalVersion.validate_skip(cs, weak) + return t_GlobalVersion.validate_skip(ops, cs, weak) && m_ == 8; case cons9: - return t_Hashmap_32_True.validate_skip(cs, weak) + return t_Hashmap_32_True.validate_skip(ops, cs, weak) && m_ == 9; case cons12: - return t_HashmapE_32_WorkchainDescr.validate_skip(cs, weak) + return t_HashmapE_32_WorkchainDescr.validate_skip(ops, cs, weak) && m_ == 12; case cons14: - return t_BlockCreateFees.validate_skip(cs, weak) + return t_BlockCreateFees.validate_skip(ops, cs, weak) && m_ == 14; case cons15: return cs.advance(128) @@ -15205,61 +15496,61 @@ bool ConfigParam::validate_skip(vm::CellSlice& cs, bool weak) const { && m_ == 16; } case cons17: - return t_Grams.validate_skip(cs, weak) - && t_Grams.validate_skip(cs, weak) - && t_Grams.validate_skip(cs, weak) + return t_Grams.validate_skip(ops, cs, weak) + && t_Grams.validate_skip(ops, cs, weak) + && t_Grams.validate_skip(ops, cs, weak) && cs.advance(32) && m_ == 17; case cons18: - return t_Hashmap_32_StoragePrices.validate_skip(cs, weak) + return t_Hashmap_32_StoragePrices.validate_skip(ops, cs, weak) && m_ == 18; case config_mc_gas_prices: - return t_GasLimitsPrices.validate_skip(cs, weak) + return t_GasLimitsPrices.validate_skip(ops, cs, weak) && m_ == 20; case config_gas_prices: - return t_GasLimitsPrices.validate_skip(cs, weak) + return t_GasLimitsPrices.validate_skip(ops, cs, weak) && m_ == 21; case config_mc_block_limits: - return t_BlockLimits.validate_skip(cs, weak) + return t_BlockLimits.validate_skip(ops, cs, weak) && m_ == 22; case config_block_limits: - return t_BlockLimits.validate_skip(cs, weak) + return t_BlockLimits.validate_skip(ops, cs, weak) && m_ == 23; case config_mc_fwd_prices: - return t_MsgForwardPrices.validate_skip(cs, weak) + return t_MsgForwardPrices.validate_skip(ops, cs, weak) && m_ == 24; case config_fwd_prices: - return t_MsgForwardPrices.validate_skip(cs, weak) + return t_MsgForwardPrices.validate_skip(ops, cs, weak) && m_ == 25; case cons28: - return t_CatchainConfig.validate_skip(cs, weak) + return t_CatchainConfig.validate_skip(ops, cs, weak) && m_ == 28; case cons29: - return t_ConsensusConfig.validate_skip(cs, weak) + return t_ConsensusConfig.validate_skip(ops, cs, weak) && m_ == 29; case cons31: - return t_HashmapE_256_True.validate_skip(cs, weak) + return t_HashmapE_256_True.validate_skip(ops, cs, weak) && m_ == 31; case cons32: - return t_ValidatorSet.validate_skip(cs, weak) + return t_ValidatorSet.validate_skip(ops, cs, weak) && m_ == 32; case cons33: - return t_ValidatorSet.validate_skip(cs, weak) + return t_ValidatorSet.validate_skip(ops, cs, weak) && m_ == 33; case cons34: - return t_ValidatorSet.validate_skip(cs, weak) + return t_ValidatorSet.validate_skip(ops, cs, weak) && m_ == 34; case cons35: - return t_ValidatorSet.validate_skip(cs, weak) + return t_ValidatorSet.validate_skip(ops, cs, weak) && m_ == 35; case cons36: - return t_ValidatorSet.validate_skip(cs, weak) + return t_ValidatorSet.validate_skip(ops, cs, weak) && m_ == 36; case cons37: - return t_ValidatorSet.validate_skip(cs, weak) + return t_ValidatorSet.validate_skip(ops, cs, weak) && m_ == 37; case cons39: - return t_HashmapE_256_ValidatorSignedTempKey.validate_skip(cs, weak) + return t_HashmapE_256_ValidatorSignedTempKey.validate_skip(ops, cs, weak) && m_ == 39; } return false; @@ -16780,9 +17071,9 @@ bool BlockSignaturesPure::skip(vm::CellSlice& cs) const { && t_HashmapE_16_CryptoSignaturePair.skip(cs); } -bool BlockSignaturesPure::validate_skip(vm::CellSlice& cs, bool weak) const { +bool BlockSignaturesPure::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { return cs.advance(96) - && t_HashmapE_16_CryptoSignaturePair.validate_skip(cs, weak); + && t_HashmapE_16_CryptoSignaturePair.validate_skip(ops, cs, weak); } bool BlockSignaturesPure::unpack(vm::CellSlice& cs, BlockSignaturesPure::Record& data) const { @@ -16856,10 +17147,10 @@ bool BlockSignatures::skip(vm::CellSlice& cs) const { && t_BlockSignaturesPure.skip(cs); } -bool BlockSignatures::validate_skip(vm::CellSlice& cs, bool weak) const { +bool BlockSignatures::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { return cs.fetch_ulong(8) == 17 && cs.advance(64) - && t_BlockSignaturesPure.validate_skip(cs, weak); + && t_BlockSignaturesPure.validate_skip(ops, cs, weak); } bool BlockSignatures::unpack(vm::CellSlice& cs, BlockSignatures::Record& data) const { @@ -16934,11 +17225,11 @@ bool BlockProof::skip(vm::CellSlice& cs) const { && t_Maybe_Ref_BlockSignatures.skip(cs); } -bool BlockProof::validate_skip(vm::CellSlice& cs, bool weak) const { +bool BlockProof::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { return cs.fetch_ulong(8) == 0xc3 - && t_BlockIdExt.validate_skip(cs, weak) + && t_BlockIdExt.validate_skip(ops, cs, weak) && cs.advance_refs(1) - && t_Maybe_Ref_BlockSignatures.validate_skip(cs, weak); + && t_Maybe_Ref_BlockSignatures.validate_skip(ops, cs, weak); } bool BlockProof::unpack(vm::CellSlice& cs, BlockProof::Record& data) const { @@ -17038,7 +17329,7 @@ bool ProofChain::skip(vm::CellSlice& cs) const { return false; } -bool ProofChain::validate_skip(vm::CellSlice& cs, bool weak) const { +bool ProofChain::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case chain_empty: return m_ == 0; @@ -17046,7 +17337,7 @@ bool ProofChain::validate_skip(vm::CellSlice& cs, bool weak) const { int n; return add_r1(n, 1, m_) && cs.advance_refs(1) - && (!n || ProofChain{n}.validate_skip_ref(cs, weak)); + && (!n || ProofChain{n}.validate_skip_ref(ops, cs, weak)); } } return false; @@ -17176,15 +17467,15 @@ bool TopBlockDescr::skip(vm::CellSlice& cs) const { && ProofChain{len}.skip(cs); } -bool TopBlockDescr::validate_skip(vm::CellSlice& cs, bool weak) const { +bool TopBlockDescr::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { int len; return cs.fetch_ulong(8) == 0xd5 - && t_BlockIdExt.validate_skip(cs, weak) - && t_Maybe_Ref_BlockSignatures.validate_skip(cs, weak) + && t_BlockIdExt.validate_skip(ops, cs, weak) + && t_Maybe_Ref_BlockSignatures.validate_skip(ops, cs, weak) && cs.fetch_uint_to(8, len) && 1 <= len && len <= 8 - && ProofChain{len}.validate_skip(cs, weak); + && ProofChain{len}.validate_skip(ops, cs, weak); } bool TopBlockDescr::unpack(vm::CellSlice& cs, TopBlockDescr::Record& data) const { @@ -17251,9 +17542,9 @@ bool TopBlockDescrSet::skip(vm::CellSlice& cs) const { && t_HashmapE_96_Ref_TopBlockDescr.skip(cs); } -bool TopBlockDescrSet::validate_skip(vm::CellSlice& cs, bool weak) const { +bool TopBlockDescrSet::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { return cs.fetch_ulong(32) == 0x4ac789f3 - && t_HashmapE_96_Ref_TopBlockDescr.validate_skip(cs, weak); + && t_HashmapE_96_Ref_TopBlockDescr.validate_skip(ops, cs, weak); } bool TopBlockDescrSet::unpack(vm::CellSlice& cs, TopBlockDescrSet::Record& data) const { @@ -17308,6 +17599,3450 @@ bool TopBlockDescrSet::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const { const TopBlockDescrSet t_TopBlockDescrSet; +// +// code for type `VmCellSlice` +// + +int VmCellSlice::check_tag(const vm::CellSlice& cs) const { + return cons1; +} + +bool VmCellSlice::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + int st_bits, end_bits, st_ref, end_ref; + return cs.advance_refs(1) + && cs.fetch_uint_to(10, st_bits) + && cs.fetch_uint_to(10, end_bits) + && st_bits <= end_bits + && cs.fetch_uint_leq(4, st_ref) + && cs.fetch_uint_leq(4, end_ref) + && st_ref <= end_ref; +} + +bool VmCellSlice::unpack(vm::CellSlice& cs, VmCellSlice::Record& data) const { + return cs.fetch_ref_to(data.cell) + && cs.fetch_uint_to(10, data.st_bits) + && cs.fetch_uint_to(10, data.end_bits) + && data.st_bits <= data.end_bits + && cs.fetch_uint_leq(4, data.st_ref) + && cs.fetch_uint_leq(4, data.end_ref) + && data.st_ref <= data.end_ref; +} + +bool VmCellSlice::cell_unpack(Ref cell_ref, VmCellSlice::Record& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool VmCellSlice::pack(vm::CellBuilder& cb, const VmCellSlice::Record& data) const { + return cb.store_ref_bool(data.cell) + && cb.store_ulong_rchk_bool(data.st_bits, 10) + && cb.store_ulong_rchk_bool(data.end_bits, 10) + && data.st_bits <= data.end_bits + && cb.store_uint_leq(4, data.st_ref) + && cb.store_uint_leq(4, data.end_ref) + && data.st_ref <= data.end_ref; +} + +bool VmCellSlice::cell_pack(Ref& cell_ref, const VmCellSlice::Record& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool VmCellSlice::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const { + int st_bits, end_bits, st_ref, end_ref; + return pp.open() + && pp.field("cell") + && t_Anything.print_ref(pp, cs.fetch_ref()) + && cs.fetch_uint_to(10, st_bits) + && pp.field_int(st_bits, "st_bits") + && cs.fetch_uint_to(10, end_bits) + && pp.field_int(end_bits, "end_bits") + && st_bits <= end_bits + && cs.fetch_uint_leq(4, st_ref) + && pp.field_int(st_ref, "st_ref") + && cs.fetch_uint_leq(4, end_ref) + && pp.field_int(end_ref, "end_ref") + && st_ref <= end_ref + && pp.close(); +} + +const VmCellSlice t_VmCellSlice; + +// +// code for type `VmTupleRef` +// + +int VmTupleRef::get_tag(const vm::CellSlice& cs) const { + // distinguish by parameter `m_` using 1 2 3 3 + // static inline size_t nat_abs(int x) { return (x > 1) * 2 + (x & 1); } + static signed char ctab[4] = { vm_tupref_nil, vm_tupref_single, vm_tupref_any, vm_tupref_any }; + return ctab[nat_abs(m_)]; +} + +int VmTupleRef::check_tag(const vm::CellSlice& cs) const { + switch (get_tag(cs)) { + case vm_tupref_nil: + return vm_tupref_nil; + case vm_tupref_single: + return vm_tupref_single; + case vm_tupref_any: + return vm_tupref_any; + } + return -1; +} + +bool VmTupleRef::skip(vm::CellSlice& cs) const { + switch (get_tag(cs)) { + case vm_tupref_nil: + return m_ == 0; + case vm_tupref_single: + return cs.advance_refs(1) + && m_ == 1; + case vm_tupref_any: { + int n; + return add_r1(n, 2, m_) + && cs.advance_refs(1); + } + } + return false; +} + +bool VmTupleRef::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + switch (get_tag(cs)) { + case vm_tupref_nil: + return m_ == 0; + case vm_tupref_single: + return t_VmStackValue.validate_skip_ref(ops, cs, weak) + && m_ == 1; + case vm_tupref_any: { + int n; + return add_r1(n, 2, m_) + && VmTuple{n + 2}.validate_skip_ref(ops, cs, weak); + } + } + return false; +} + +bool VmTupleRef::unpack(vm::CellSlice& cs, VmTupleRef::Record_vm_tupref_nil& data) const { + return m_ == 0; +} + +bool VmTupleRef::unpack_vm_tupref_nil(vm::CellSlice& cs) const { + return m_ == 0; +} + +bool VmTupleRef::cell_unpack(Ref cell_ref, VmTupleRef::Record_vm_tupref_nil& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool VmTupleRef::cell_unpack_vm_tupref_nil(Ref cell_ref) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_vm_tupref_nil(cs) && cs.empty_ext(); +} + +bool VmTupleRef::unpack(vm::CellSlice& cs, VmTupleRef::Record_vm_tupref_single& data) const { + return cs.fetch_ref_to(data.entry) + && m_ == 1; +} + +bool VmTupleRef::unpack_vm_tupref_single(vm::CellSlice& cs, Ref& entry) const { + return cs.fetch_ref_to(entry) + && m_ == 1; +} + +bool VmTupleRef::cell_unpack(Ref cell_ref, VmTupleRef::Record_vm_tupref_single& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool VmTupleRef::cell_unpack_vm_tupref_single(Ref cell_ref, Ref& entry) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_vm_tupref_single(cs, entry) && cs.empty_ext(); +} + +bool VmTupleRef::unpack(vm::CellSlice& cs, VmTupleRef::Record_vm_tupref_any& data) const { + return add_r1(data.n, 2, m_) + && cs.fetch_ref_to(data.ref); +} + +bool VmTupleRef::unpack_vm_tupref_any(vm::CellSlice& cs, int& n, Ref& ref) const { + return add_r1(n, 2, m_) + && cs.fetch_ref_to(ref); +} + +bool VmTupleRef::cell_unpack(Ref cell_ref, VmTupleRef::Record_vm_tupref_any& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool VmTupleRef::cell_unpack_vm_tupref_any(Ref cell_ref, int& n, Ref& ref) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_vm_tupref_any(cs, n, ref) && cs.empty_ext(); +} + +bool VmTupleRef::pack(vm::CellBuilder& cb, const VmTupleRef::Record_vm_tupref_nil& data) const { + return m_ == 0; +} + +bool VmTupleRef::pack_vm_tupref_nil(vm::CellBuilder& cb) const { + return m_ == 0; +} + +bool VmTupleRef::cell_pack(Ref& cell_ref, const VmTupleRef::Record_vm_tupref_nil& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool VmTupleRef::cell_pack_vm_tupref_nil(Ref& cell_ref) const { + vm::CellBuilder cb; + return pack_vm_tupref_nil(cb) && std::move(cb).finalize_to(cell_ref); +} + +bool VmTupleRef::pack(vm::CellBuilder& cb, const VmTupleRef::Record_vm_tupref_single& data) const { + return cb.store_ref_bool(data.entry) + && m_ == 1; +} + +bool VmTupleRef::pack_vm_tupref_single(vm::CellBuilder& cb, Ref entry) const { + return cb.store_ref_bool(entry) + && m_ == 1; +} + +bool VmTupleRef::cell_pack(Ref& cell_ref, const VmTupleRef::Record_vm_tupref_single& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool VmTupleRef::cell_pack_vm_tupref_single(Ref& cell_ref, Ref entry) const { + vm::CellBuilder cb; + return pack_vm_tupref_single(cb, std::move(entry)) && std::move(cb).finalize_to(cell_ref); +} + +bool VmTupleRef::pack(vm::CellBuilder& cb, const VmTupleRef::Record_vm_tupref_any& data) const { + int n; + return add_r1(n, 2, m_) + && cb.store_ref_bool(data.ref); +} + +bool VmTupleRef::pack_vm_tupref_any(vm::CellBuilder& cb, Ref ref) const { + int n; + return add_r1(n, 2, m_) + && cb.store_ref_bool(ref); +} + +bool VmTupleRef::cell_pack(Ref& cell_ref, const VmTupleRef::Record_vm_tupref_any& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool VmTupleRef::cell_pack_vm_tupref_any(Ref& cell_ref, Ref ref) const { + vm::CellBuilder cb; + return pack_vm_tupref_any(cb, std::move(ref)) && std::move(cb).finalize_to(cell_ref); +} + +bool VmTupleRef::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const { + switch (get_tag(cs)) { + case vm_tupref_nil: + return pp.cons("vm_tupref_nil") + && m_ == 0; + case vm_tupref_single: + return pp.open("vm_tupref_single") + && pp.field("entry") + && t_VmStackValue.print_ref(pp, cs.fetch_ref()) + && m_ == 1 + && pp.close(); + case vm_tupref_any: { + int n; + return pp.open("vm_tupref_any") + && add_r1(n, 2, m_) + && pp.field("ref") + && VmTuple{n + 2}.print_ref(pp, cs.fetch_ref()) + && pp.close(); + } + } + return pp.fail("unknown constructor for VmTupleRef"); +} + + +// +// code for type `VmTuple` +// + +int VmTuple::get_tag(const vm::CellSlice& cs) const { + // distinguish by parameter `m_` using 1 2 2 2 + return m_ ? vm_tuple_tcons : vm_tuple_nil; +} + +int VmTuple::check_tag(const vm::CellSlice& cs) const { + switch (get_tag(cs)) { + case vm_tuple_nil: + return vm_tuple_nil; + case vm_tuple_tcons: + return vm_tuple_tcons; + } + return -1; +} + +bool VmTuple::skip(vm::CellSlice& cs) const { + switch (get_tag(cs)) { + case vm_tuple_nil: + return m_ == 0; + case vm_tuple_tcons: { + int n; + return add_r1(n, 1, m_) + && VmTupleRef{n}.skip(cs) + && cs.advance_refs(1); + } + } + return false; +} + +bool VmTuple::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + switch (get_tag(cs)) { + case vm_tuple_nil: + return m_ == 0; + case vm_tuple_tcons: { + int n; + return add_r1(n, 1, m_) + && VmTupleRef{n}.validate_skip(ops, cs, weak) + && t_VmStackValue.validate_skip_ref(ops, cs, weak); + } + } + return false; +} + +bool VmTuple::unpack(vm::CellSlice& cs, VmTuple::Record_vm_tuple_nil& data) const { + return m_ == 0; +} + +bool VmTuple::unpack_vm_tuple_nil(vm::CellSlice& cs) const { + return m_ == 0; +} + +bool VmTuple::cell_unpack(Ref cell_ref, VmTuple::Record_vm_tuple_nil& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool VmTuple::cell_unpack_vm_tuple_nil(Ref cell_ref) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_vm_tuple_nil(cs) && cs.empty_ext(); +} + +bool VmTuple::unpack(vm::CellSlice& cs, VmTuple::Record_vm_tuple_tcons& data) const { + return add_r1(data.n, 1, m_) + && VmTupleRef{data.n}.fetch_to(cs, data.head) + && cs.fetch_ref_to(data.tail); +} + +bool VmTuple::unpack_vm_tuple_tcons(vm::CellSlice& cs, int& n, Ref& head, Ref& tail) const { + return add_r1(n, 1, m_) + && VmTupleRef{n}.fetch_to(cs, head) + && cs.fetch_ref_to(tail); +} + +bool VmTuple::cell_unpack(Ref cell_ref, VmTuple::Record_vm_tuple_tcons& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool VmTuple::cell_unpack_vm_tuple_tcons(Ref cell_ref, int& n, Ref& head, Ref& tail) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_vm_tuple_tcons(cs, n, head, tail) && cs.empty_ext(); +} + +bool VmTuple::pack(vm::CellBuilder& cb, const VmTuple::Record_vm_tuple_nil& data) const { + return m_ == 0; +} + +bool VmTuple::pack_vm_tuple_nil(vm::CellBuilder& cb) const { + return m_ == 0; +} + +bool VmTuple::cell_pack(Ref& cell_ref, const VmTuple::Record_vm_tuple_nil& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool VmTuple::cell_pack_vm_tuple_nil(Ref& cell_ref) const { + vm::CellBuilder cb; + return pack_vm_tuple_nil(cb) && std::move(cb).finalize_to(cell_ref); +} + +bool VmTuple::pack(vm::CellBuilder& cb, const VmTuple::Record_vm_tuple_tcons& data) const { + int n; + return add_r1(n, 1, m_) + && VmTupleRef{n}.store_from(cb, data.head) + && cb.store_ref_bool(data.tail); +} + +bool VmTuple::pack_vm_tuple_tcons(vm::CellBuilder& cb, Ref head, Ref tail) const { + int n; + return add_r1(n, 1, m_) + && VmTupleRef{n}.store_from(cb, head) + && cb.store_ref_bool(tail); +} + +bool VmTuple::cell_pack(Ref& cell_ref, const VmTuple::Record_vm_tuple_tcons& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool VmTuple::cell_pack_vm_tuple_tcons(Ref& cell_ref, Ref head, Ref tail) const { + vm::CellBuilder cb; + return pack_vm_tuple_tcons(cb, std::move(head), std::move(tail)) && std::move(cb).finalize_to(cell_ref); +} + +bool VmTuple::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const { + switch (get_tag(cs)) { + case vm_tuple_nil: + return pp.cons("vm_tuple_nil") + && m_ == 0; + case vm_tuple_tcons: { + int n; + return pp.open("vm_tuple_tcons") + && add_r1(n, 1, m_) + && pp.field("head") + && VmTupleRef{n}.print_skip(pp, cs) + && pp.field("tail") + && t_VmStackValue.print_ref(pp, cs.fetch_ref()) + && pp.close(); + } + } + return pp.fail("unknown constructor for VmTuple"); +} + + +// +// code for type `VmStackValue` +// +constexpr char VmStackValue::cons_len[9]; +constexpr unsigned short VmStackValue::cons_tag[9]; + +int VmStackValue::get_tag(const vm::CellSlice& cs) const { + switch (cs.bselect(6, 7)) { + case 0: + if (cs.bit_at(6)) { + if (cs.bit_at(7)) { + return vm_stk_cell; + } else { + return cs.bit_at(8) ? vm_stk_nan : vm_stk_int; + } + } else { + return cs.bit_at(7) ? vm_stk_tinyint : vm_stk_null; + } + case 1: + if (cs.bit_at(6)) { + return cs.bit_at(7) ? vm_stk_tuple : vm_stk_cont; + } else { + return cs.bit_at(7) ? vm_stk_builder : vm_stk_slice; + } + default: + return -1; + } +} + +int VmStackValue::check_tag(const vm::CellSlice& cs) const { + switch (get_tag(cs)) { + case vm_stk_null: + return cs.prefetch_ulong(8) == 0 ? vm_stk_null : -1; + case vm_stk_tinyint: + return cs.prefetch_ulong(8) == 1 ? vm_stk_tinyint : -1; + case vm_stk_int: + return cs.prefetch_ulong(15) == 0x100 ? vm_stk_int : -1; + case vm_stk_nan: + return cs.prefetch_ulong(16) == 0x2ff ? vm_stk_nan : -1; + case vm_stk_cell: + return cs.prefetch_ulong(8) == 3 ? vm_stk_cell : -1; + case vm_stk_slice: + return cs.prefetch_ulong(8) == 4 ? vm_stk_slice : -1; + case vm_stk_builder: + return cs.prefetch_ulong(8) == 5 ? vm_stk_builder : -1; + case vm_stk_cont: + return cs.prefetch_ulong(8) == 6 ? vm_stk_cont : -1; + case vm_stk_tuple: + return cs.prefetch_ulong(8) == 7 ? vm_stk_tuple : -1; + } + return -1; +} + +bool VmStackValue::skip(vm::CellSlice& cs) const { + switch (get_tag(cs)) { + case vm_stk_null: + return cs.advance(8); + case vm_stk_tinyint: + return cs.advance(72); + case vm_stk_int: + return cs.advance(272); + case vm_stk_nan: + return cs.advance(16); + case vm_stk_cell: + return cs.advance_ext(0x10008); + case vm_stk_slice: + return cs.advance_ext(0x10022); + case vm_stk_builder: + return cs.advance_ext(0x10008); + case vm_stk_cont: + return cs.advance(8) + && t_VmCont.skip(cs); + case vm_stk_tuple: { + int len; + return cs.advance(8) + && cs.fetch_uint_to(16, len) + && VmTuple{len}.skip(cs); + } + } + return false; +} + +bool VmStackValue::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + switch (get_tag(cs)) { + case vm_stk_null: + return cs.fetch_ulong(8) == 0; + case vm_stk_tinyint: + return cs.fetch_ulong(8) == 1 + && cs.advance(64); + case vm_stk_int: + return cs.fetch_ulong(15) == 0x100 + && cs.advance(257); + case vm_stk_nan: + return cs.fetch_ulong(16) == 0x2ff; + case vm_stk_cell: + return cs.fetch_ulong(8) == 3 + && cs.advance_refs(1); + case vm_stk_slice: + return cs.fetch_ulong(8) == 4 + && t_VmCellSlice.validate_skip(ops, cs, weak); + case vm_stk_builder: + return cs.fetch_ulong(8) == 5 + && cs.advance_refs(1); + case vm_stk_cont: + return cs.fetch_ulong(8) == 6 + && t_VmCont.validate_skip(ops, cs, weak); + case vm_stk_tuple: { + int len; + return cs.fetch_ulong(8) == 7 + && cs.fetch_uint_to(16, len) + && VmTuple{len}.validate_skip(ops, cs, weak); + } + } + return false; +} + +bool VmStackValue::unpack(vm::CellSlice& cs, VmStackValue::Record_vm_stk_null& data) const { + return cs.fetch_ulong(8) == 0; +} + +bool VmStackValue::unpack_vm_stk_null(vm::CellSlice& cs) const { + return cs.fetch_ulong(8) == 0; +} + +bool VmStackValue::cell_unpack(Ref cell_ref, VmStackValue::Record_vm_stk_null& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool VmStackValue::cell_unpack_vm_stk_null(Ref cell_ref) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_vm_stk_null(cs) && cs.empty_ext(); +} + +bool VmStackValue::unpack(vm::CellSlice& cs, VmStackValue::Record_vm_stk_tinyint& data) const { + return cs.fetch_ulong(8) == 1 + && cs.fetch_int_to(64, data.value); +} + +bool VmStackValue::unpack_vm_stk_tinyint(vm::CellSlice& cs, long long& value) const { + return cs.fetch_ulong(8) == 1 + && cs.fetch_int_to(64, value); +} + +bool VmStackValue::cell_unpack(Ref cell_ref, VmStackValue::Record_vm_stk_tinyint& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool VmStackValue::cell_unpack_vm_stk_tinyint(Ref cell_ref, long long& value) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_vm_stk_tinyint(cs, value) && cs.empty_ext(); +} + +bool VmStackValue::unpack(vm::CellSlice& cs, VmStackValue::Record_vm_stk_int& data) const { + return cs.fetch_ulong(15) == 0x100 + && cs.fetch_int256_to(257, data.value); +} + +bool VmStackValue::unpack_vm_stk_int(vm::CellSlice& cs, RefInt256& value) const { + return cs.fetch_ulong(15) == 0x100 + && cs.fetch_int256_to(257, value); +} + +bool VmStackValue::cell_unpack(Ref cell_ref, VmStackValue::Record_vm_stk_int& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool VmStackValue::cell_unpack_vm_stk_int(Ref cell_ref, RefInt256& value) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_vm_stk_int(cs, value) && cs.empty_ext(); +} + +bool VmStackValue::unpack(vm::CellSlice& cs, VmStackValue::Record_vm_stk_nan& data) const { + return cs.fetch_ulong(16) == 0x2ff; +} + +bool VmStackValue::unpack_vm_stk_nan(vm::CellSlice& cs) const { + return cs.fetch_ulong(16) == 0x2ff; +} + +bool VmStackValue::cell_unpack(Ref cell_ref, VmStackValue::Record_vm_stk_nan& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool VmStackValue::cell_unpack_vm_stk_nan(Ref cell_ref) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_vm_stk_nan(cs) && cs.empty_ext(); +} + +bool VmStackValue::unpack(vm::CellSlice& cs, VmStackValue::Record_vm_stk_cell& data) const { + return cs.fetch_ulong(8) == 3 + && cs.fetch_ref_to(data.cell); +} + +bool VmStackValue::unpack_vm_stk_cell(vm::CellSlice& cs, Ref& cell) const { + return cs.fetch_ulong(8) == 3 + && cs.fetch_ref_to(cell); +} + +bool VmStackValue::cell_unpack(Ref cell_ref, VmStackValue::Record_vm_stk_cell& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool VmStackValue::cell_unpack_vm_stk_cell(Ref cell_ref, Ref& cell) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_vm_stk_cell(cs, cell) && cs.empty_ext(); +} + +bool VmStackValue::unpack(vm::CellSlice& cs, VmStackValue::Record_vm_stk_slice& data) const { + return cs.fetch_ulong(8) == 4 + && cs.fetch_subslice_ext_to(0x1001a, data.x); +} + +bool VmStackValue::unpack_vm_stk_slice(vm::CellSlice& cs, Ref& x) const { + return cs.fetch_ulong(8) == 4 + && cs.fetch_subslice_ext_to(0x1001a, x); +} + +bool VmStackValue::cell_unpack(Ref cell_ref, VmStackValue::Record_vm_stk_slice& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool VmStackValue::cell_unpack_vm_stk_slice(Ref cell_ref, Ref& x) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_vm_stk_slice(cs, x) && cs.empty_ext(); +} + +bool VmStackValue::unpack(vm::CellSlice& cs, VmStackValue::Record_vm_stk_builder& data) const { + return cs.fetch_ulong(8) == 5 + && cs.fetch_ref_to(data.cell); +} + +bool VmStackValue::unpack_vm_stk_builder(vm::CellSlice& cs, Ref& cell) const { + return cs.fetch_ulong(8) == 5 + && cs.fetch_ref_to(cell); +} + +bool VmStackValue::cell_unpack(Ref cell_ref, VmStackValue::Record_vm_stk_builder& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool VmStackValue::cell_unpack_vm_stk_builder(Ref cell_ref, Ref& cell) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_vm_stk_builder(cs, cell) && cs.empty_ext(); +} + +bool VmStackValue::unpack(vm::CellSlice& cs, VmStackValue::Record_vm_stk_cont& data) const { + return cs.fetch_ulong(8) == 6 + && t_VmCont.fetch_to(cs, data.cont); +} + +bool VmStackValue::unpack_vm_stk_cont(vm::CellSlice& cs, Ref& cont) const { + return cs.fetch_ulong(8) == 6 + && t_VmCont.fetch_to(cs, cont); +} + +bool VmStackValue::cell_unpack(Ref cell_ref, VmStackValue::Record_vm_stk_cont& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool VmStackValue::cell_unpack_vm_stk_cont(Ref cell_ref, Ref& cont) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_vm_stk_cont(cs, cont) && cs.empty_ext(); +} + +bool VmStackValue::unpack(vm::CellSlice& cs, VmStackValue::Record_vm_stk_tuple& data) const { + return cs.fetch_ulong(8) == 7 + && cs.fetch_uint_to(16, data.len) + && VmTuple{data.len}.fetch_to(cs, data.data); +} + +bool VmStackValue::unpack_vm_stk_tuple(vm::CellSlice& cs, int& len, Ref& data) const { + return cs.fetch_ulong(8) == 7 + && cs.fetch_uint_to(16, len) + && VmTuple{len}.fetch_to(cs, data); +} + +bool VmStackValue::cell_unpack(Ref cell_ref, VmStackValue::Record_vm_stk_tuple& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool VmStackValue::cell_unpack_vm_stk_tuple(Ref cell_ref, int& len, Ref& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_vm_stk_tuple(cs, len, data) && cs.empty_ext(); +} + +bool VmStackValue::pack(vm::CellBuilder& cb, const VmStackValue::Record_vm_stk_null& data) const { + return cb.store_long_bool(0, 8); +} + +bool VmStackValue::pack_vm_stk_null(vm::CellBuilder& cb) const { + return cb.store_long_bool(0, 8); +} + +bool VmStackValue::cell_pack(Ref& cell_ref, const VmStackValue::Record_vm_stk_null& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool VmStackValue::cell_pack_vm_stk_null(Ref& cell_ref) const { + vm::CellBuilder cb; + return pack_vm_stk_null(cb) && std::move(cb).finalize_to(cell_ref); +} + +bool VmStackValue::pack(vm::CellBuilder& cb, const VmStackValue::Record_vm_stk_tinyint& data) const { + return cb.store_long_bool(1, 8) + && cb.store_long_rchk_bool(data.value, 64); +} + +bool VmStackValue::pack_vm_stk_tinyint(vm::CellBuilder& cb, long long value) const { + return cb.store_long_bool(1, 8) + && cb.store_long_rchk_bool(value, 64); +} + +bool VmStackValue::cell_pack(Ref& cell_ref, const VmStackValue::Record_vm_stk_tinyint& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool VmStackValue::cell_pack_vm_stk_tinyint(Ref& cell_ref, long long value) const { + vm::CellBuilder cb; + return pack_vm_stk_tinyint(cb, value) && std::move(cb).finalize_to(cell_ref); +} + +bool VmStackValue::pack(vm::CellBuilder& cb, const VmStackValue::Record_vm_stk_int& data) const { + return cb.store_long_bool(0x100, 15) + && cb.store_int256_bool(data.value, 257); +} + +bool VmStackValue::pack_vm_stk_int(vm::CellBuilder& cb, RefInt256 value) const { + return cb.store_long_bool(0x100, 15) + && cb.store_int256_bool(value, 257); +} + +bool VmStackValue::cell_pack(Ref& cell_ref, const VmStackValue::Record_vm_stk_int& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool VmStackValue::cell_pack_vm_stk_int(Ref& cell_ref, RefInt256 value) const { + vm::CellBuilder cb; + return pack_vm_stk_int(cb, std::move(value)) && std::move(cb).finalize_to(cell_ref); +} + +bool VmStackValue::pack(vm::CellBuilder& cb, const VmStackValue::Record_vm_stk_nan& data) const { + return cb.store_long_bool(0x2ff, 16); +} + +bool VmStackValue::pack_vm_stk_nan(vm::CellBuilder& cb) const { + return cb.store_long_bool(0x2ff, 16); +} + +bool VmStackValue::cell_pack(Ref& cell_ref, const VmStackValue::Record_vm_stk_nan& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool VmStackValue::cell_pack_vm_stk_nan(Ref& cell_ref) const { + vm::CellBuilder cb; + return pack_vm_stk_nan(cb) && std::move(cb).finalize_to(cell_ref); +} + +bool VmStackValue::pack(vm::CellBuilder& cb, const VmStackValue::Record_vm_stk_cell& data) const { + return cb.store_long_bool(3, 8) + && cb.store_ref_bool(data.cell); +} + +bool VmStackValue::pack_vm_stk_cell(vm::CellBuilder& cb, Ref cell) const { + return cb.store_long_bool(3, 8) + && cb.store_ref_bool(cell); +} + +bool VmStackValue::cell_pack(Ref& cell_ref, const VmStackValue::Record_vm_stk_cell& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool VmStackValue::cell_pack_vm_stk_cell(Ref& cell_ref, Ref cell) const { + vm::CellBuilder cb; + return pack_vm_stk_cell(cb, std::move(cell)) && std::move(cb).finalize_to(cell_ref); +} + +bool VmStackValue::pack(vm::CellBuilder& cb, const VmStackValue::Record_vm_stk_slice& data) const { + return cb.store_long_bool(4, 8) + && cb.append_cellslice_chk(data.x, 0x1001a); +} + +bool VmStackValue::pack_vm_stk_slice(vm::CellBuilder& cb, Ref x) const { + return cb.store_long_bool(4, 8) + && cb.append_cellslice_chk(x, 0x1001a); +} + +bool VmStackValue::cell_pack(Ref& cell_ref, const VmStackValue::Record_vm_stk_slice& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool VmStackValue::cell_pack_vm_stk_slice(Ref& cell_ref, Ref x) const { + vm::CellBuilder cb; + return pack_vm_stk_slice(cb, std::move(x)) && std::move(cb).finalize_to(cell_ref); +} + +bool VmStackValue::pack(vm::CellBuilder& cb, const VmStackValue::Record_vm_stk_builder& data) const { + return cb.store_long_bool(5, 8) + && cb.store_ref_bool(data.cell); +} + +bool VmStackValue::pack_vm_stk_builder(vm::CellBuilder& cb, Ref cell) const { + return cb.store_long_bool(5, 8) + && cb.store_ref_bool(cell); +} + +bool VmStackValue::cell_pack(Ref& cell_ref, const VmStackValue::Record_vm_stk_builder& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool VmStackValue::cell_pack_vm_stk_builder(Ref& cell_ref, Ref cell) const { + vm::CellBuilder cb; + return pack_vm_stk_builder(cb, std::move(cell)) && std::move(cb).finalize_to(cell_ref); +} + +bool VmStackValue::pack(vm::CellBuilder& cb, const VmStackValue::Record_vm_stk_cont& data) const { + return cb.store_long_bool(6, 8) + && t_VmCont.store_from(cb, data.cont); +} + +bool VmStackValue::pack_vm_stk_cont(vm::CellBuilder& cb, Ref cont) const { + return cb.store_long_bool(6, 8) + && t_VmCont.store_from(cb, cont); +} + +bool VmStackValue::cell_pack(Ref& cell_ref, const VmStackValue::Record_vm_stk_cont& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool VmStackValue::cell_pack_vm_stk_cont(Ref& cell_ref, Ref cont) const { + vm::CellBuilder cb; + return pack_vm_stk_cont(cb, std::move(cont)) && std::move(cb).finalize_to(cell_ref); +} + +bool VmStackValue::pack(vm::CellBuilder& cb, const VmStackValue::Record_vm_stk_tuple& data) const { + return cb.store_long_bool(7, 8) + && cb.store_ulong_rchk_bool(data.len, 16) + && VmTuple{data.len}.store_from(cb, data.data); +} + +bool VmStackValue::pack_vm_stk_tuple(vm::CellBuilder& cb, int len, Ref data) const { + return cb.store_long_bool(7, 8) + && cb.store_ulong_rchk_bool(len, 16) + && VmTuple{len}.store_from(cb, data); +} + +bool VmStackValue::cell_pack(Ref& cell_ref, const VmStackValue::Record_vm_stk_tuple& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool VmStackValue::cell_pack_vm_stk_tuple(Ref& cell_ref, int len, Ref data) const { + vm::CellBuilder cb; + return pack_vm_stk_tuple(cb, len, std::move(data)) && std::move(cb).finalize_to(cell_ref); +} + +bool VmStackValue::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const { + switch (get_tag(cs)) { + case vm_stk_null: + return cs.fetch_ulong(8) == 0 + && pp.cons("vm_stk_null"); + case vm_stk_tinyint: + return cs.fetch_ulong(8) == 1 + && pp.open("vm_stk_tinyint") + && pp.fetch_int_field(cs, 64, "value") + && pp.close(); + case vm_stk_int: + return cs.fetch_ulong(15) == 0x100 + && pp.open("vm_stk_int") + && pp.fetch_int256_field(cs, 257, "value") + && pp.close(); + case vm_stk_nan: + return cs.fetch_ulong(16) == 0x2ff + && pp.cons("vm_stk_nan"); + case vm_stk_cell: + return cs.fetch_ulong(8) == 3 + && pp.open("vm_stk_cell") + && pp.field("cell") + && t_Anything.print_ref(pp, cs.fetch_ref()) + && pp.close(); + case vm_stk_slice: + return cs.fetch_ulong(8) == 4 + && pp.open("vm_stk_slice") + && pp.field() + && t_VmCellSlice.print_skip(pp, cs) + && pp.close(); + case vm_stk_builder: + return cs.fetch_ulong(8) == 5 + && pp.open("vm_stk_builder") + && pp.field("cell") + && t_Anything.print_ref(pp, cs.fetch_ref()) + && pp.close(); + case vm_stk_cont: + return cs.fetch_ulong(8) == 6 + && pp.open("vm_stk_cont") + && pp.field("cont") + && t_VmCont.print_skip(pp, cs) + && pp.close(); + case vm_stk_tuple: { + int len; + return cs.fetch_ulong(8) == 7 + && pp.open("vm_stk_tuple") + && cs.fetch_uint_to(16, len) + && pp.field_int(len, "len") + && pp.field("data") + && VmTuple{len}.print_skip(pp, cs) + && pp.close(); + } + } + return pp.fail("unknown constructor for VmStackValue"); +} + +const VmStackValue t_VmStackValue; + +// +// code for type `VmStack` +// + +int VmStack::check_tag(const vm::CellSlice& cs) const { + return vm_stack; +} + +bool VmStack::skip(vm::CellSlice& cs) const { + int depth; + return cs.fetch_uint_to(24, depth) + && VmStackList{depth}.skip(cs); +} + +bool VmStack::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + int depth; + return cs.fetch_uint_to(24, depth) + && VmStackList{depth}.validate_skip(ops, cs, weak); +} + +bool VmStack::unpack(vm::CellSlice& cs, VmStack::Record& data) const { + return cs.fetch_uint_to(24, data.depth) + && VmStackList{data.depth}.fetch_to(cs, data.stack); +} + +bool VmStack::unpack_vm_stack(vm::CellSlice& cs, int& depth, Ref& stack) const { + return cs.fetch_uint_to(24, depth) + && VmStackList{depth}.fetch_to(cs, stack); +} + +bool VmStack::cell_unpack(Ref cell_ref, VmStack::Record& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool VmStack::cell_unpack_vm_stack(Ref cell_ref, int& depth, Ref& stack) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_vm_stack(cs, depth, stack) && cs.empty_ext(); +} + +bool VmStack::pack(vm::CellBuilder& cb, const VmStack::Record& data) const { + return cb.store_ulong_rchk_bool(data.depth, 24) + && VmStackList{data.depth}.store_from(cb, data.stack); +} + +bool VmStack::pack_vm_stack(vm::CellBuilder& cb, int depth, Ref stack) const { + return cb.store_ulong_rchk_bool(depth, 24) + && VmStackList{depth}.store_from(cb, stack); +} + +bool VmStack::cell_pack(Ref& cell_ref, const VmStack::Record& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool VmStack::cell_pack_vm_stack(Ref& cell_ref, int depth, Ref stack) const { + vm::CellBuilder cb; + return pack_vm_stack(cb, depth, std::move(stack)) && std::move(cb).finalize_to(cell_ref); +} + +bool VmStack::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const { + int depth; + return pp.open("vm_stack") + && cs.fetch_uint_to(24, depth) + && pp.field_int(depth, "depth") + && pp.field("stack") + && VmStackList{depth}.print_skip(pp, cs) + && pp.close(); +} + +const VmStack t_VmStack; + +// +// code for type `VmStackList` +// + +int VmStackList::get_tag(const vm::CellSlice& cs) const { + // distinguish by parameter `m_` using 2 1 1 1 + return m_ ? vm_stk_cons : vm_stk_nil; +} + +int VmStackList::check_tag(const vm::CellSlice& cs) const { + switch (get_tag(cs)) { + case vm_stk_cons: + return vm_stk_cons; + case vm_stk_nil: + return vm_stk_nil; + } + return -1; +} + +bool VmStackList::skip(vm::CellSlice& cs) const { + switch (get_tag(cs)) { + case vm_stk_cons: { + int n; + return add_r1(n, 1, m_) + && cs.advance_refs(1) + && t_VmStackValue.skip(cs); + } + case vm_stk_nil: + return m_ == 0; + } + return false; +} + +bool VmStackList::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + switch (get_tag(cs)) { + case vm_stk_cons: { + int n; + return add_r1(n, 1, m_) + && VmStackList{n}.validate_skip_ref(ops, cs, weak) + && t_VmStackValue.validate_skip(ops, cs, weak); + } + case vm_stk_nil: + return m_ == 0; + } + return false; +} + +bool VmStackList::unpack(vm::CellSlice& cs, VmStackList::Record_vm_stk_cons& data) const { + return add_r1(data.n, 1, m_) + && cs.fetch_ref_to(data.rest) + && t_VmStackValue.fetch_to(cs, data.tos); +} + +bool VmStackList::unpack_vm_stk_cons(vm::CellSlice& cs, int& n, Ref& rest, Ref& tos) const { + return add_r1(n, 1, m_) + && cs.fetch_ref_to(rest) + && t_VmStackValue.fetch_to(cs, tos); +} + +bool VmStackList::cell_unpack(Ref cell_ref, VmStackList::Record_vm_stk_cons& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool VmStackList::cell_unpack_vm_stk_cons(Ref cell_ref, int& n, Ref& rest, Ref& tos) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_vm_stk_cons(cs, n, rest, tos) && cs.empty_ext(); +} + +bool VmStackList::unpack(vm::CellSlice& cs, VmStackList::Record_vm_stk_nil& data) const { + return m_ == 0; +} + +bool VmStackList::unpack_vm_stk_nil(vm::CellSlice& cs) const { + return m_ == 0; +} + +bool VmStackList::cell_unpack(Ref cell_ref, VmStackList::Record_vm_stk_nil& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool VmStackList::cell_unpack_vm_stk_nil(Ref cell_ref) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_vm_stk_nil(cs) && cs.empty_ext(); +} + +bool VmStackList::pack(vm::CellBuilder& cb, const VmStackList::Record_vm_stk_cons& data) const { + int n; + return add_r1(n, 1, m_) + && cb.store_ref_bool(data.rest) + && t_VmStackValue.store_from(cb, data.tos); +} + +bool VmStackList::pack_vm_stk_cons(vm::CellBuilder& cb, Ref rest, Ref tos) const { + int n; + return add_r1(n, 1, m_) + && cb.store_ref_bool(rest) + && t_VmStackValue.store_from(cb, tos); +} + +bool VmStackList::cell_pack(Ref& cell_ref, const VmStackList::Record_vm_stk_cons& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool VmStackList::cell_pack_vm_stk_cons(Ref& cell_ref, Ref rest, Ref tos) const { + vm::CellBuilder cb; + return pack_vm_stk_cons(cb, std::move(rest), std::move(tos)) && std::move(cb).finalize_to(cell_ref); +} + +bool VmStackList::pack(vm::CellBuilder& cb, const VmStackList::Record_vm_stk_nil& data) const { + return m_ == 0; +} + +bool VmStackList::pack_vm_stk_nil(vm::CellBuilder& cb) const { + return m_ == 0; +} + +bool VmStackList::cell_pack(Ref& cell_ref, const VmStackList::Record_vm_stk_nil& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool VmStackList::cell_pack_vm_stk_nil(Ref& cell_ref) const { + vm::CellBuilder cb; + return pack_vm_stk_nil(cb) && std::move(cb).finalize_to(cell_ref); +} + +bool VmStackList::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const { + switch (get_tag(cs)) { + case vm_stk_cons: { + int n; + return pp.open("vm_stk_cons") + && add_r1(n, 1, m_) + && pp.field("rest") + && VmStackList{n}.print_ref(pp, cs.fetch_ref()) + && pp.field("tos") + && t_VmStackValue.print_skip(pp, cs) + && pp.close(); + } + case vm_stk_nil: + return pp.cons("vm_stk_nil") + && m_ == 0; + } + return pp.fail("unknown constructor for VmStackList"); +} + + +// +// code for type `VmSaveList` +// + +int VmSaveList::check_tag(const vm::CellSlice& cs) const { + return cons1; +} + +bool VmSaveList::skip(vm::CellSlice& cs) const { + return t_HashmapE_4_VmStackValue.skip(cs); +} + +bool VmSaveList::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_HashmapE_4_VmStackValue.validate_skip(ops, cs, weak); +} + +bool VmSaveList::unpack(vm::CellSlice& cs, VmSaveList::Record& data) const { + return t_HashmapE_4_VmStackValue.fetch_to(cs, data.cregs); +} + +bool VmSaveList::unpack_cons1(vm::CellSlice& cs, Ref& cregs) const { + return t_HashmapE_4_VmStackValue.fetch_to(cs, cregs); +} + +bool VmSaveList::cell_unpack(Ref cell_ref, VmSaveList::Record& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool VmSaveList::cell_unpack_cons1(Ref cell_ref, Ref& cregs) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_cons1(cs, cregs) && cs.empty_ext(); +} + +bool VmSaveList::pack(vm::CellBuilder& cb, const VmSaveList::Record& data) const { + return t_HashmapE_4_VmStackValue.store_from(cb, data.cregs); +} + +bool VmSaveList::pack_cons1(vm::CellBuilder& cb, Ref cregs) const { + return t_HashmapE_4_VmStackValue.store_from(cb, cregs); +} + +bool VmSaveList::cell_pack(Ref& cell_ref, const VmSaveList::Record& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool VmSaveList::cell_pack_cons1(Ref& cell_ref, Ref cregs) const { + vm::CellBuilder cb; + return pack_cons1(cb, std::move(cregs)) && std::move(cb).finalize_to(cell_ref); +} + +bool VmSaveList::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const { + return pp.open() + && pp.field("cregs") + && t_HashmapE_4_VmStackValue.print_skip(pp, cs) + && pp.close(); +} + +const VmSaveList t_VmSaveList; + +// +// code for auxiliary type `VmGasLimits_aux` +// + +int VmGasLimits_aux::check_tag(const vm::CellSlice& cs) const { + return cons1; +} + +bool VmGasLimits_aux::unpack(vm::CellSlice& cs, VmGasLimits_aux::Record& data) const { + return cs.fetch_int_to(64, data.max_limit) + && cs.fetch_int_to(64, data.cur_limit) + && cs.fetch_int_to(64, data.credit); +} + +bool VmGasLimits_aux::unpack_cons1(vm::CellSlice& cs, long long& max_limit, long long& cur_limit, long long& credit) const { + return cs.fetch_int_to(64, max_limit) + && cs.fetch_int_to(64, cur_limit) + && cs.fetch_int_to(64, credit); +} + +bool VmGasLimits_aux::cell_unpack(Ref cell_ref, VmGasLimits_aux::Record& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool VmGasLimits_aux::cell_unpack_cons1(Ref cell_ref, long long& max_limit, long long& cur_limit, long long& credit) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_cons1(cs, max_limit, cur_limit, credit) && cs.empty_ext(); +} + +bool VmGasLimits_aux::pack(vm::CellBuilder& cb, const VmGasLimits_aux::Record& data) const { + return cb.store_long_rchk_bool(data.max_limit, 64) + && cb.store_long_rchk_bool(data.cur_limit, 64) + && cb.store_long_rchk_bool(data.credit, 64); +} + +bool VmGasLimits_aux::pack_cons1(vm::CellBuilder& cb, long long max_limit, long long cur_limit, long long credit) const { + return cb.store_long_rchk_bool(max_limit, 64) + && cb.store_long_rchk_bool(cur_limit, 64) + && cb.store_long_rchk_bool(credit, 64); +} + +bool VmGasLimits_aux::cell_pack(Ref& cell_ref, const VmGasLimits_aux::Record& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool VmGasLimits_aux::cell_pack_cons1(Ref& cell_ref, long long max_limit, long long cur_limit, long long credit) const { + vm::CellBuilder cb; + return pack_cons1(cb, max_limit, cur_limit, credit) && std::move(cb).finalize_to(cell_ref); +} + +bool VmGasLimits_aux::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const { + return pp.open() + && pp.fetch_int_field(cs, 64, "max_limit") + && pp.fetch_int_field(cs, 64, "cur_limit") + && pp.fetch_int_field(cs, 64, "credit") + && pp.close(); +} + +const VmGasLimits_aux t_VmGasLimits_aux; + +// +// code for type `VmGasLimits` +// + +int VmGasLimits::check_tag(const vm::CellSlice& cs) const { + return gas_limits; +} + +bool VmGasLimits::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return cs.advance(64) + && t_VmGasLimits_aux.validate_skip_ref(ops, cs, weak); +} + +bool VmGasLimits::unpack(vm::CellSlice& cs, VmGasLimits::Record& data) const { + return cs.fetch_int_to(64, data.remaining) + && t_VmGasLimits_aux.cell_unpack(cs.fetch_ref(), data.r1); +} + +bool VmGasLimits::cell_unpack(Ref cell_ref, VmGasLimits::Record& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool VmGasLimits::pack(vm::CellBuilder& cb, const VmGasLimits::Record& data) const { + Ref tmp_cell; + return cb.store_long_rchk_bool(data.remaining, 64) + && t_VmGasLimits_aux.cell_pack(tmp_cell, data.r1) + && cb.store_ref_bool(std::move(tmp_cell)); +} + +bool VmGasLimits::cell_pack(Ref& cell_ref, const VmGasLimits::Record& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool VmGasLimits::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const { + return pp.open("gas_limits") + && pp.fetch_int_field(cs, 64, "remaining") + && pp.field() + && t_VmGasLimits_aux.print_ref(pp, cs.fetch_ref()) + && pp.close(); +} + +const VmGasLimits t_VmGasLimits; + +// +// code for type `VmLibraries` +// + +int VmLibraries::check_tag(const vm::CellSlice& cs) const { + return cons1; +} + +bool VmLibraries::skip(vm::CellSlice& cs) const { + return t_HashmapE_256_Ref_Cell.skip(cs); +} + +bool VmLibraries::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_HashmapE_256_Ref_Cell.validate_skip(ops, cs, weak); +} + +bool VmLibraries::unpack(vm::CellSlice& cs, VmLibraries::Record& data) const { + return t_HashmapE_256_Ref_Cell.fetch_to(cs, data.libraries); +} + +bool VmLibraries::unpack_cons1(vm::CellSlice& cs, Ref& libraries) const { + return t_HashmapE_256_Ref_Cell.fetch_to(cs, libraries); +} + +bool VmLibraries::cell_unpack(Ref cell_ref, VmLibraries::Record& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool VmLibraries::cell_unpack_cons1(Ref cell_ref, Ref& libraries) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_cons1(cs, libraries) && cs.empty_ext(); +} + +bool VmLibraries::pack(vm::CellBuilder& cb, const VmLibraries::Record& data) const { + return t_HashmapE_256_Ref_Cell.store_from(cb, data.libraries); +} + +bool VmLibraries::pack_cons1(vm::CellBuilder& cb, Ref libraries) const { + return t_HashmapE_256_Ref_Cell.store_from(cb, libraries); +} + +bool VmLibraries::cell_pack(Ref& cell_ref, const VmLibraries::Record& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool VmLibraries::cell_pack_cons1(Ref& cell_ref, Ref libraries) const { + vm::CellBuilder cb; + return pack_cons1(cb, std::move(libraries)) && std::move(cb).finalize_to(cell_ref); +} + +bool VmLibraries::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const { + return pp.open() + && pp.field("libraries") + && t_HashmapE_256_Ref_Cell.print_skip(pp, cs) + && pp.close(); +} + +const VmLibraries t_VmLibraries; + +// +// code for type `VmControlData` +// + +int VmControlData::check_tag(const vm::CellSlice& cs) const { + return vm_ctl_data; +} + +bool VmControlData::skip(vm::CellSlice& cs) const { + return t_Maybe_uint13.skip(cs) + && t_Maybe_VmStack.skip(cs) + && t_VmSaveList.skip(cs) + && t_Maybe_int16.skip(cs); +} + +bool VmControlData::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_Maybe_uint13.validate_skip(ops, cs, weak) + && t_Maybe_VmStack.validate_skip(ops, cs, weak) + && t_VmSaveList.validate_skip(ops, cs, weak) + && t_Maybe_int16.validate_skip(ops, cs, weak); +} + +bool VmControlData::unpack(vm::CellSlice& cs, VmControlData::Record& data) const { + return t_Maybe_uint13.fetch_to(cs, data.nargs) + && t_Maybe_VmStack.fetch_to(cs, data.stack) + && t_VmSaveList.fetch_to(cs, data.save) + && t_Maybe_int16.fetch_to(cs, data.cp); +} + +bool VmControlData::cell_unpack(Ref cell_ref, VmControlData::Record& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool VmControlData::pack(vm::CellBuilder& cb, const VmControlData::Record& data) const { + return t_Maybe_uint13.store_from(cb, data.nargs) + && t_Maybe_VmStack.store_from(cb, data.stack) + && t_VmSaveList.store_from(cb, data.save) + && t_Maybe_int16.store_from(cb, data.cp); +} + +bool VmControlData::cell_pack(Ref& cell_ref, const VmControlData::Record& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool VmControlData::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const { + return pp.open("vm_ctl_data") + && pp.field("nargs") + && t_Maybe_uint13.print_skip(pp, cs) + && pp.field("stack") + && t_Maybe_VmStack.print_skip(pp, cs) + && pp.field("save") + && t_VmSaveList.print_skip(pp, cs) + && pp.field("cp") + && t_Maybe_int16.print_skip(pp, cs) + && pp.close(); +} + +const VmControlData t_VmControlData; + +// +// code for type `VmCont` +// +constexpr char VmCont::cons_len[10]; +constexpr unsigned char VmCont::cons_tag[10]; + +int VmCont::check_tag(const vm::CellSlice& cs) const { + switch (get_tag(cs)) { + case vmc_std: + return cs.have(2) ? vmc_std : -1; + case vmc_envelope: + return cs.have(2) ? vmc_envelope : -1; + case vmc_quit: + return cs.have(4) ? vmc_quit : -1; + case vmc_quit_exc: + return cs.have(4) ? vmc_quit_exc : -1; + case vmc_repeat: + return cs.prefetch_ulong(5) == 20 ? vmc_repeat : -1; + case vmc_until: + return cs.have(6) ? vmc_until : -1; + case vmc_again: + return cs.have(6) ? vmc_again : -1; + case vmc_while_cond: + return cs.have(6) ? vmc_while_cond : -1; + case vmc_while_body: + return cs.prefetch_ulong(6) == 0x33 ? vmc_while_body : -1; + case vmc_pushint: + return cs.have(4) ? vmc_pushint : -1; + } + return -1; +} + +bool VmCont::skip(vm::CellSlice& cs) const { + switch (get_tag(cs)) { + case vmc_std: + return cs.advance(2) + && t_VmControlData.skip(cs) + && cs.advance_ext(0x1001a); + case vmc_envelope: + return cs.advance(2) + && t_VmControlData.skip(cs) + && cs.advance_refs(1); + case vmc_quit: + return cs.advance(36); + case vmc_quit_exc: + return cs.advance(4); + case vmc_repeat: + return cs.advance_ext(0x20044); + case vmc_until: + return cs.advance_ext(0x20006); + case vmc_again: + return cs.advance_ext(0x10006); + case vmc_while_cond: + return cs.advance_ext(0x30006); + case vmc_while_body: + return cs.advance_ext(0x30006); + case vmc_pushint: + return cs.advance_ext(0x10024); + } + return false; +} + +bool VmCont::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + switch (get_tag(cs)) { + case vmc_std: + return cs.advance(2) + && t_VmControlData.validate_skip(ops, cs, weak) + && t_VmCellSlice.validate_skip(ops, cs, weak); + case vmc_envelope: + return cs.advance(2) + && t_VmControlData.validate_skip(ops, cs, weak) + && validate_skip_ref(ops, cs, weak); + case vmc_quit: + return cs.advance(36); + case vmc_quit_exc: + return cs.advance(4); + case vmc_repeat: + return cs.fetch_ulong(5) == 20 + && cs.advance(63) + && validate_skip_ref(ops, cs, weak) + && validate_skip_ref(ops, cs, weak); + case vmc_until: + return cs.advance(6) + && validate_skip_ref(ops, cs, weak) + && validate_skip_ref(ops, cs, weak); + case vmc_again: + return cs.advance(6) + && validate_skip_ref(ops, cs, weak); + case vmc_while_cond: + return cs.advance(6) + && validate_skip_ref(ops, cs, weak) + && validate_skip_ref(ops, cs, weak) + && validate_skip_ref(ops, cs, weak); + case vmc_while_body: + return cs.fetch_ulong(6) == 0x33 + && validate_skip_ref(ops, cs, weak) + && validate_skip_ref(ops, cs, weak) + && validate_skip_ref(ops, cs, weak); + case vmc_pushint: + return cs.advance(36) + && validate_skip_ref(ops, cs, weak); + } + return false; +} + +bool VmCont::unpack(vm::CellSlice& cs, VmCont::Record_vmc_std& data) const { + return cs.fetch_ulong(2) == 0 + && t_VmControlData.fetch_to(cs, data.cdata) + && cs.fetch_subslice_ext_to(0x1001a, data.code); +} + +bool VmCont::unpack_vmc_std(vm::CellSlice& cs, Ref& cdata, Ref& code) const { + return cs.fetch_ulong(2) == 0 + && t_VmControlData.fetch_to(cs, cdata) + && cs.fetch_subslice_ext_to(0x1001a, code); +} + +bool VmCont::cell_unpack(Ref cell_ref, VmCont::Record_vmc_std& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool VmCont::cell_unpack_vmc_std(Ref cell_ref, Ref& cdata, Ref& code) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_vmc_std(cs, cdata, code) && cs.empty_ext(); +} + +bool VmCont::unpack(vm::CellSlice& cs, VmCont::Record_vmc_envelope& data) const { + return cs.fetch_ulong(2) == 1 + && t_VmControlData.fetch_to(cs, data.cdata) + && cs.fetch_ref_to(data.next); +} + +bool VmCont::unpack_vmc_envelope(vm::CellSlice& cs, Ref& cdata, Ref& next) const { + return cs.fetch_ulong(2) == 1 + && t_VmControlData.fetch_to(cs, cdata) + && cs.fetch_ref_to(next); +} + +bool VmCont::cell_unpack(Ref cell_ref, VmCont::Record_vmc_envelope& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool VmCont::cell_unpack_vmc_envelope(Ref cell_ref, Ref& cdata, Ref& next) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_vmc_envelope(cs, cdata, next) && cs.empty_ext(); +} + +bool VmCont::unpack(vm::CellSlice& cs, VmCont::Record_vmc_quit& data) const { + return cs.fetch_ulong(4) == 8 + && cs.fetch_int_to(32, data.exit_code); +} + +bool VmCont::unpack_vmc_quit(vm::CellSlice& cs, int& exit_code) const { + return cs.fetch_ulong(4) == 8 + && cs.fetch_int_to(32, exit_code); +} + +bool VmCont::cell_unpack(Ref cell_ref, VmCont::Record_vmc_quit& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool VmCont::cell_unpack_vmc_quit(Ref cell_ref, int& exit_code) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_vmc_quit(cs, exit_code) && cs.empty_ext(); +} + +bool VmCont::unpack(vm::CellSlice& cs, VmCont::Record_vmc_quit_exc& data) const { + return cs.fetch_ulong(4) == 9; +} + +bool VmCont::unpack_vmc_quit_exc(vm::CellSlice& cs) const { + return cs.fetch_ulong(4) == 9; +} + +bool VmCont::cell_unpack(Ref cell_ref, VmCont::Record_vmc_quit_exc& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool VmCont::cell_unpack_vmc_quit_exc(Ref cell_ref) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_vmc_quit_exc(cs) && cs.empty_ext(); +} + +bool VmCont::unpack(vm::CellSlice& cs, VmCont::Record_vmc_repeat& data) const { + return cs.fetch_ulong(5) == 20 + && cs.fetch_uint_to(63, data.count) + && cs.fetch_ref_to(data.body) + && cs.fetch_ref_to(data.after); +} + +bool VmCont::unpack_vmc_repeat(vm::CellSlice& cs, long long& count, Ref& body, Ref& after) const { + return cs.fetch_ulong(5) == 20 + && cs.fetch_uint_to(63, count) + && cs.fetch_ref_to(body) + && cs.fetch_ref_to(after); +} + +bool VmCont::cell_unpack(Ref cell_ref, VmCont::Record_vmc_repeat& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool VmCont::cell_unpack_vmc_repeat(Ref cell_ref, long long& count, Ref& body, Ref& after) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_vmc_repeat(cs, count, body, after) && cs.empty_ext(); +} + +bool VmCont::unpack(vm::CellSlice& cs, VmCont::Record_vmc_until& data) const { + return cs.fetch_ulong(6) == 0x30 + && cs.fetch_ref_to(data.body) + && cs.fetch_ref_to(data.after); +} + +bool VmCont::unpack_vmc_until(vm::CellSlice& cs, Ref& body, Ref& after) const { + return cs.fetch_ulong(6) == 0x30 + && cs.fetch_ref_to(body) + && cs.fetch_ref_to(after); +} + +bool VmCont::cell_unpack(Ref cell_ref, VmCont::Record_vmc_until& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool VmCont::cell_unpack_vmc_until(Ref cell_ref, Ref& body, Ref& after) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_vmc_until(cs, body, after) && cs.empty_ext(); +} + +bool VmCont::unpack(vm::CellSlice& cs, VmCont::Record_vmc_again& data) const { + return cs.fetch_ulong(6) == 0x31 + && cs.fetch_ref_to(data.body); +} + +bool VmCont::unpack_vmc_again(vm::CellSlice& cs, Ref& body) const { + return cs.fetch_ulong(6) == 0x31 + && cs.fetch_ref_to(body); +} + +bool VmCont::cell_unpack(Ref cell_ref, VmCont::Record_vmc_again& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool VmCont::cell_unpack_vmc_again(Ref cell_ref, Ref& body) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_vmc_again(cs, body) && cs.empty_ext(); +} + +bool VmCont::unpack(vm::CellSlice& cs, VmCont::Record_vmc_while_cond& data) const { + return cs.fetch_ulong(6) == 0x32 + && cs.fetch_ref_to(data.cond) + && cs.fetch_ref_to(data.body) + && cs.fetch_ref_to(data.after); +} + +bool VmCont::unpack_vmc_while_cond(vm::CellSlice& cs, Ref& cond, Ref& body, Ref& after) const { + return cs.fetch_ulong(6) == 0x32 + && cs.fetch_ref_to(cond) + && cs.fetch_ref_to(body) + && cs.fetch_ref_to(after); +} + +bool VmCont::cell_unpack(Ref cell_ref, VmCont::Record_vmc_while_cond& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool VmCont::cell_unpack_vmc_while_cond(Ref cell_ref, Ref& cond, Ref& body, Ref& after) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_vmc_while_cond(cs, cond, body, after) && cs.empty_ext(); +} + +bool VmCont::unpack(vm::CellSlice& cs, VmCont::Record_vmc_while_body& data) const { + return cs.fetch_ulong(6) == 0x33 + && cs.fetch_ref_to(data.cond) + && cs.fetch_ref_to(data.body) + && cs.fetch_ref_to(data.after); +} + +bool VmCont::unpack_vmc_while_body(vm::CellSlice& cs, Ref& cond, Ref& body, Ref& after) const { + return cs.fetch_ulong(6) == 0x33 + && cs.fetch_ref_to(cond) + && cs.fetch_ref_to(body) + && cs.fetch_ref_to(after); +} + +bool VmCont::cell_unpack(Ref cell_ref, VmCont::Record_vmc_while_body& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool VmCont::cell_unpack_vmc_while_body(Ref cell_ref, Ref& cond, Ref& body, Ref& after) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_vmc_while_body(cs, cond, body, after) && cs.empty_ext(); +} + +bool VmCont::unpack(vm::CellSlice& cs, VmCont::Record_vmc_pushint& data) const { + return cs.fetch_ulong(4) == 15 + && cs.fetch_int_to(32, data.value) + && cs.fetch_ref_to(data.next); +} + +bool VmCont::unpack_vmc_pushint(vm::CellSlice& cs, int& value, Ref& next) const { + return cs.fetch_ulong(4) == 15 + && cs.fetch_int_to(32, value) + && cs.fetch_ref_to(next); +} + +bool VmCont::cell_unpack(Ref cell_ref, VmCont::Record_vmc_pushint& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool VmCont::cell_unpack_vmc_pushint(Ref cell_ref, int& value, Ref& next) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_vmc_pushint(cs, value, next) && cs.empty_ext(); +} + +bool VmCont::pack(vm::CellBuilder& cb, const VmCont::Record_vmc_std& data) const { + return cb.store_long_bool(0, 2) + && t_VmControlData.store_from(cb, data.cdata) + && cb.append_cellslice_chk(data.code, 0x1001a); +} + +bool VmCont::pack_vmc_std(vm::CellBuilder& cb, Ref cdata, Ref code) const { + return cb.store_long_bool(0, 2) + && t_VmControlData.store_from(cb, cdata) + && cb.append_cellslice_chk(code, 0x1001a); +} + +bool VmCont::cell_pack(Ref& cell_ref, const VmCont::Record_vmc_std& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool VmCont::cell_pack_vmc_std(Ref& cell_ref, Ref cdata, Ref code) const { + vm::CellBuilder cb; + return pack_vmc_std(cb, std::move(cdata), std::move(code)) && std::move(cb).finalize_to(cell_ref); +} + +bool VmCont::pack(vm::CellBuilder& cb, const VmCont::Record_vmc_envelope& data) const { + return cb.store_long_bool(1, 2) + && t_VmControlData.store_from(cb, data.cdata) + && cb.store_ref_bool(data.next); +} + +bool VmCont::pack_vmc_envelope(vm::CellBuilder& cb, Ref cdata, Ref next) const { + return cb.store_long_bool(1, 2) + && t_VmControlData.store_from(cb, cdata) + && cb.store_ref_bool(next); +} + +bool VmCont::cell_pack(Ref& cell_ref, const VmCont::Record_vmc_envelope& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool VmCont::cell_pack_vmc_envelope(Ref& cell_ref, Ref cdata, Ref next) const { + vm::CellBuilder cb; + return pack_vmc_envelope(cb, std::move(cdata), std::move(next)) && std::move(cb).finalize_to(cell_ref); +} + +bool VmCont::pack(vm::CellBuilder& cb, const VmCont::Record_vmc_quit& data) const { + return cb.store_long_bool(8, 4) + && cb.store_long_rchk_bool(data.exit_code, 32); +} + +bool VmCont::pack_vmc_quit(vm::CellBuilder& cb, int exit_code) const { + return cb.store_long_bool(8, 4) + && cb.store_long_rchk_bool(exit_code, 32); +} + +bool VmCont::cell_pack(Ref& cell_ref, const VmCont::Record_vmc_quit& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool VmCont::cell_pack_vmc_quit(Ref& cell_ref, int exit_code) const { + vm::CellBuilder cb; + return pack_vmc_quit(cb, exit_code) && std::move(cb).finalize_to(cell_ref); +} + +bool VmCont::pack(vm::CellBuilder& cb, const VmCont::Record_vmc_quit_exc& data) const { + return cb.store_long_bool(9, 4); +} + +bool VmCont::pack_vmc_quit_exc(vm::CellBuilder& cb) const { + return cb.store_long_bool(9, 4); +} + +bool VmCont::cell_pack(Ref& cell_ref, const VmCont::Record_vmc_quit_exc& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool VmCont::cell_pack_vmc_quit_exc(Ref& cell_ref) const { + vm::CellBuilder cb; + return pack_vmc_quit_exc(cb) && std::move(cb).finalize_to(cell_ref); +} + +bool VmCont::pack(vm::CellBuilder& cb, const VmCont::Record_vmc_repeat& data) const { + return cb.store_long_bool(20, 5) + && cb.store_ulong_rchk_bool(data.count, 63) + && cb.store_ref_bool(data.body) + && cb.store_ref_bool(data.after); +} + +bool VmCont::pack_vmc_repeat(vm::CellBuilder& cb, long long count, Ref body, Ref after) const { + return cb.store_long_bool(20, 5) + && cb.store_ulong_rchk_bool(count, 63) + && cb.store_ref_bool(body) + && cb.store_ref_bool(after); +} + +bool VmCont::cell_pack(Ref& cell_ref, const VmCont::Record_vmc_repeat& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool VmCont::cell_pack_vmc_repeat(Ref& cell_ref, long long count, Ref body, Ref after) const { + vm::CellBuilder cb; + return pack_vmc_repeat(cb, count, std::move(body), std::move(after)) && std::move(cb).finalize_to(cell_ref); +} + +bool VmCont::pack(vm::CellBuilder& cb, const VmCont::Record_vmc_until& data) const { + return cb.store_long_bool(0x30, 6) + && cb.store_ref_bool(data.body) + && cb.store_ref_bool(data.after); +} + +bool VmCont::pack_vmc_until(vm::CellBuilder& cb, Ref body, Ref after) const { + return cb.store_long_bool(0x30, 6) + && cb.store_ref_bool(body) + && cb.store_ref_bool(after); +} + +bool VmCont::cell_pack(Ref& cell_ref, const VmCont::Record_vmc_until& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool VmCont::cell_pack_vmc_until(Ref& cell_ref, Ref body, Ref after) const { + vm::CellBuilder cb; + return pack_vmc_until(cb, std::move(body), std::move(after)) && std::move(cb).finalize_to(cell_ref); +} + +bool VmCont::pack(vm::CellBuilder& cb, const VmCont::Record_vmc_again& data) const { + return cb.store_long_bool(0x31, 6) + && cb.store_ref_bool(data.body); +} + +bool VmCont::pack_vmc_again(vm::CellBuilder& cb, Ref body) const { + return cb.store_long_bool(0x31, 6) + && cb.store_ref_bool(body); +} + +bool VmCont::cell_pack(Ref& cell_ref, const VmCont::Record_vmc_again& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool VmCont::cell_pack_vmc_again(Ref& cell_ref, Ref body) const { + vm::CellBuilder cb; + return pack_vmc_again(cb, std::move(body)) && std::move(cb).finalize_to(cell_ref); +} + +bool VmCont::pack(vm::CellBuilder& cb, const VmCont::Record_vmc_while_cond& data) const { + return cb.store_long_bool(0x32, 6) + && cb.store_ref_bool(data.cond) + && cb.store_ref_bool(data.body) + && cb.store_ref_bool(data.after); +} + +bool VmCont::pack_vmc_while_cond(vm::CellBuilder& cb, Ref cond, Ref body, Ref after) const { + return cb.store_long_bool(0x32, 6) + && cb.store_ref_bool(cond) + && cb.store_ref_bool(body) + && cb.store_ref_bool(after); +} + +bool VmCont::cell_pack(Ref& cell_ref, const VmCont::Record_vmc_while_cond& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool VmCont::cell_pack_vmc_while_cond(Ref& cell_ref, Ref cond, Ref body, Ref after) const { + vm::CellBuilder cb; + return pack_vmc_while_cond(cb, std::move(cond), std::move(body), std::move(after)) && std::move(cb).finalize_to(cell_ref); +} + +bool VmCont::pack(vm::CellBuilder& cb, const VmCont::Record_vmc_while_body& data) const { + return cb.store_long_bool(0x33, 6) + && cb.store_ref_bool(data.cond) + && cb.store_ref_bool(data.body) + && cb.store_ref_bool(data.after); +} + +bool VmCont::pack_vmc_while_body(vm::CellBuilder& cb, Ref cond, Ref body, Ref after) const { + return cb.store_long_bool(0x33, 6) + && cb.store_ref_bool(cond) + && cb.store_ref_bool(body) + && cb.store_ref_bool(after); +} + +bool VmCont::cell_pack(Ref& cell_ref, const VmCont::Record_vmc_while_body& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool VmCont::cell_pack_vmc_while_body(Ref& cell_ref, Ref cond, Ref body, Ref after) const { + vm::CellBuilder cb; + return pack_vmc_while_body(cb, std::move(cond), std::move(body), std::move(after)) && std::move(cb).finalize_to(cell_ref); +} + +bool VmCont::pack(vm::CellBuilder& cb, const VmCont::Record_vmc_pushint& data) const { + return cb.store_long_bool(15, 4) + && cb.store_long_rchk_bool(data.value, 32) + && cb.store_ref_bool(data.next); +} + +bool VmCont::pack_vmc_pushint(vm::CellBuilder& cb, int value, Ref next) const { + return cb.store_long_bool(15, 4) + && cb.store_long_rchk_bool(value, 32) + && cb.store_ref_bool(next); +} + +bool VmCont::cell_pack(Ref& cell_ref, const VmCont::Record_vmc_pushint& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool VmCont::cell_pack_vmc_pushint(Ref& cell_ref, int value, Ref next) const { + vm::CellBuilder cb; + return pack_vmc_pushint(cb, value, std::move(next)) && std::move(cb).finalize_to(cell_ref); +} + +bool VmCont::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const { + switch (get_tag(cs)) { + case vmc_std: + return cs.advance(2) + && pp.open("vmc_std") + && pp.field("cdata") + && t_VmControlData.print_skip(pp, cs) + && pp.field("code") + && t_VmCellSlice.print_skip(pp, cs) + && pp.close(); + case vmc_envelope: + return cs.advance(2) + && pp.open("vmc_envelope") + && pp.field("cdata") + && t_VmControlData.print_skip(pp, cs) + && pp.field("next") + && print_ref(pp, cs.fetch_ref()) + && pp.close(); + case vmc_quit: + return cs.advance(4) + && pp.open("vmc_quit") + && pp.fetch_int_field(cs, 32, "exit_code") + && pp.close(); + case vmc_quit_exc: + return cs.advance(4) + && pp.cons("vmc_quit_exc"); + case vmc_repeat: + return cs.fetch_ulong(5) == 20 + && pp.open("vmc_repeat") + && pp.fetch_uint_field(cs, 63, "count") + && pp.field("body") + && print_ref(pp, cs.fetch_ref()) + && pp.field("after") + && print_ref(pp, cs.fetch_ref()) + && pp.close(); + case vmc_until: + return cs.advance(6) + && pp.open("vmc_until") + && pp.field("body") + && print_ref(pp, cs.fetch_ref()) + && pp.field("after") + && print_ref(pp, cs.fetch_ref()) + && pp.close(); + case vmc_again: + return cs.advance(6) + && pp.open("vmc_again") + && pp.field("body") + && print_ref(pp, cs.fetch_ref()) + && pp.close(); + case vmc_while_cond: + return cs.advance(6) + && pp.open("vmc_while_cond") + && pp.field("cond") + && print_ref(pp, cs.fetch_ref()) + && pp.field("body") + && print_ref(pp, cs.fetch_ref()) + && pp.field("after") + && print_ref(pp, cs.fetch_ref()) + && pp.close(); + case vmc_while_body: + return cs.fetch_ulong(6) == 0x33 + && pp.open("vmc_while_body") + && pp.field("cond") + && print_ref(pp, cs.fetch_ref()) + && pp.field("body") + && print_ref(pp, cs.fetch_ref()) + && pp.field("after") + && print_ref(pp, cs.fetch_ref()) + && pp.close(); + case vmc_pushint: + return cs.advance(4) + && pp.open("vmc_pushint") + && pp.fetch_int_field(cs, 32, "value") + && pp.field("next") + && print_ref(pp, cs.fetch_ref()) + && pp.close(); + } + return pp.fail("unknown constructor for VmCont"); +} + +const VmCont t_VmCont; + +// +// code for type `DNS_RecordSet` +// + +int DNS_RecordSet::check_tag(const vm::CellSlice& cs) const { + return cons1; +} + +bool DNS_RecordSet::skip(vm::CellSlice& cs) const { + return t_HashmapE_16_Ref_DNSRecord.skip(cs); +} + +bool DNS_RecordSet::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_HashmapE_16_Ref_DNSRecord.validate_skip(ops, cs, weak); +} + +bool DNS_RecordSet::unpack(vm::CellSlice& cs, DNS_RecordSet::Record& data) const { + return t_HashmapE_16_Ref_DNSRecord.fetch_to(cs, data.x); +} + +bool DNS_RecordSet::unpack_cons1(vm::CellSlice& cs, Ref& x) const { + return t_HashmapE_16_Ref_DNSRecord.fetch_to(cs, x); +} + +bool DNS_RecordSet::cell_unpack(Ref cell_ref, DNS_RecordSet::Record& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool DNS_RecordSet::cell_unpack_cons1(Ref cell_ref, Ref& x) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_cons1(cs, x) && cs.empty_ext(); +} + +bool DNS_RecordSet::pack(vm::CellBuilder& cb, const DNS_RecordSet::Record& data) const { + return t_HashmapE_16_Ref_DNSRecord.store_from(cb, data.x); +} + +bool DNS_RecordSet::pack_cons1(vm::CellBuilder& cb, Ref x) const { + return t_HashmapE_16_Ref_DNSRecord.store_from(cb, x); +} + +bool DNS_RecordSet::cell_pack(Ref& cell_ref, const DNS_RecordSet::Record& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool DNS_RecordSet::cell_pack_cons1(Ref& cell_ref, Ref x) const { + vm::CellBuilder cb; + return pack_cons1(cb, std::move(x)) && std::move(cb).finalize_to(cell_ref); +} + +bool DNS_RecordSet::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const { + return pp.open() + && pp.field() + && t_HashmapE_16_Ref_DNSRecord.print_skip(pp, cs) + && pp.close(); +} + +const DNS_RecordSet t_DNS_RecordSet; + +// +// code for type `TextChunkRef` +// + +int TextChunkRef::get_tag(const vm::CellSlice& cs) const { + // distinguish by parameter `m_` using 2 1 1 1 + return m_ ? chunk_ref : chunk_ref_empty; +} + +int TextChunkRef::check_tag(const vm::CellSlice& cs) const { + switch (get_tag(cs)) { + case chunk_ref: + return chunk_ref; + case chunk_ref_empty: + return chunk_ref_empty; + } + return -1; +} + +bool TextChunkRef::skip(vm::CellSlice& cs) const { + switch (get_tag(cs)) { + case chunk_ref: { + int n; + return add_r1(n, 1, m_) + && cs.advance_refs(1); + } + case chunk_ref_empty: + return m_ == 0; + } + return false; +} + +bool TextChunkRef::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + switch (get_tag(cs)) { + case chunk_ref: { + int n; + return add_r1(n, 1, m_) + && TextChunks{n + 1}.validate_skip_ref(ops, cs, weak); + } + case chunk_ref_empty: + return m_ == 0; + } + return false; +} + +bool TextChunkRef::unpack(vm::CellSlice& cs, TextChunkRef::Record_chunk_ref& data) const { + return add_r1(data.n, 1, m_) + && cs.fetch_ref_to(data.ref); +} + +bool TextChunkRef::unpack_chunk_ref(vm::CellSlice& cs, int& n, Ref& ref) const { + return add_r1(n, 1, m_) + && cs.fetch_ref_to(ref); +} + +bool TextChunkRef::cell_unpack(Ref cell_ref, TextChunkRef::Record_chunk_ref& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool TextChunkRef::cell_unpack_chunk_ref(Ref cell_ref, int& n, Ref& ref) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_chunk_ref(cs, n, ref) && cs.empty_ext(); +} + +bool TextChunkRef::unpack(vm::CellSlice& cs, TextChunkRef::Record_chunk_ref_empty& data) const { + return m_ == 0; +} + +bool TextChunkRef::unpack_chunk_ref_empty(vm::CellSlice& cs) const { + return m_ == 0; +} + +bool TextChunkRef::cell_unpack(Ref cell_ref, TextChunkRef::Record_chunk_ref_empty& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool TextChunkRef::cell_unpack_chunk_ref_empty(Ref cell_ref) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_chunk_ref_empty(cs) && cs.empty_ext(); +} + +bool TextChunkRef::pack(vm::CellBuilder& cb, const TextChunkRef::Record_chunk_ref& data) const { + int n; + return add_r1(n, 1, m_) + && cb.store_ref_bool(data.ref); +} + +bool TextChunkRef::pack_chunk_ref(vm::CellBuilder& cb, Ref ref) const { + int n; + return add_r1(n, 1, m_) + && cb.store_ref_bool(ref); +} + +bool TextChunkRef::cell_pack(Ref& cell_ref, const TextChunkRef::Record_chunk_ref& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool TextChunkRef::cell_pack_chunk_ref(Ref& cell_ref, Ref ref) const { + vm::CellBuilder cb; + return pack_chunk_ref(cb, std::move(ref)) && std::move(cb).finalize_to(cell_ref); +} + +bool TextChunkRef::pack(vm::CellBuilder& cb, const TextChunkRef::Record_chunk_ref_empty& data) const { + return m_ == 0; +} + +bool TextChunkRef::pack_chunk_ref_empty(vm::CellBuilder& cb) const { + return m_ == 0; +} + +bool TextChunkRef::cell_pack(Ref& cell_ref, const TextChunkRef::Record_chunk_ref_empty& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool TextChunkRef::cell_pack_chunk_ref_empty(Ref& cell_ref) const { + vm::CellBuilder cb; + return pack_chunk_ref_empty(cb) && std::move(cb).finalize_to(cell_ref); +} + +bool TextChunkRef::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const { + switch (get_tag(cs)) { + case chunk_ref: { + int n; + return pp.open("chunk_ref") + && add_r1(n, 1, m_) + && pp.field("ref") + && TextChunks{n + 1}.print_ref(pp, cs.fetch_ref()) + && pp.close(); + } + case chunk_ref_empty: + return pp.cons("chunk_ref_empty") + && m_ == 0; + } + return pp.fail("unknown constructor for TextChunkRef"); +} + + +// +// code for type `TextChunks` +// + +int TextChunks::get_tag(const vm::CellSlice& cs) const { + // distinguish by parameter `m_` using 2 1 1 1 + return m_ ? text_chunk : text_chunk_empty; +} + +int TextChunks::check_tag(const vm::CellSlice& cs) const { + switch (get_tag(cs)) { + case text_chunk: + return text_chunk; + case text_chunk_empty: + return text_chunk_empty; + } + return -1; +} + +bool TextChunks::skip(vm::CellSlice& cs) const { + switch (get_tag(cs)) { + case text_chunk: { + int n, len; + return add_r1(n, 1, m_) + && cs.fetch_uint_to(8, len) + && cs.advance(8 * len) + && TextChunkRef{n}.skip(cs); + } + case text_chunk_empty: + return m_ == 0; + } + return false; +} + +bool TextChunks::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + switch (get_tag(cs)) { + case text_chunk: { + int n, len; + return add_r1(n, 1, m_) + && cs.fetch_uint_to(8, len) + && cs.advance(8 * len) + && TextChunkRef{n}.validate_skip(ops, cs, weak); + } + case text_chunk_empty: + return m_ == 0; + } + return false; +} + +bool TextChunks::unpack(vm::CellSlice& cs, TextChunks::Record_text_chunk& data) const { + return add_r1(data.n, 1, m_) + && cs.fetch_uint_to(8, data.len) + && cs.fetch_bitstring_to(8 * data.len, data.data) + && TextChunkRef{data.n}.fetch_to(cs, data.next); +} + +bool TextChunks::cell_unpack(Ref cell_ref, TextChunks::Record_text_chunk& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool TextChunks::unpack(vm::CellSlice& cs, TextChunks::Record_text_chunk_empty& data) const { + return m_ == 0; +} + +bool TextChunks::unpack_text_chunk_empty(vm::CellSlice& cs) const { + return m_ == 0; +} + +bool TextChunks::cell_unpack(Ref cell_ref, TextChunks::Record_text_chunk_empty& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool TextChunks::cell_unpack_text_chunk_empty(Ref cell_ref) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_text_chunk_empty(cs) && cs.empty_ext(); +} + +bool TextChunks::pack(vm::CellBuilder& cb, const TextChunks::Record_text_chunk& data) const { + int n; + return add_r1(n, 1, m_) + && cb.store_ulong_rchk_bool(data.len, 8) + && cb.append_bitstring_chk(data.data, 8 * data.len) + && TextChunkRef{n}.store_from(cb, data.next); +} + +bool TextChunks::cell_pack(Ref& cell_ref, const TextChunks::Record_text_chunk& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool TextChunks::pack(vm::CellBuilder& cb, const TextChunks::Record_text_chunk_empty& data) const { + return m_ == 0; +} + +bool TextChunks::pack_text_chunk_empty(vm::CellBuilder& cb) const { + return m_ == 0; +} + +bool TextChunks::cell_pack(Ref& cell_ref, const TextChunks::Record_text_chunk_empty& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool TextChunks::cell_pack_text_chunk_empty(Ref& cell_ref) const { + vm::CellBuilder cb; + return pack_text_chunk_empty(cb) && std::move(cb).finalize_to(cell_ref); +} + +bool TextChunks::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const { + switch (get_tag(cs)) { + case text_chunk: { + int n, len; + return pp.open("text_chunk") + && add_r1(n, 1, m_) + && cs.fetch_uint_to(8, len) + && pp.field_int(len, "len") + && pp.fetch_bits_field(cs, 8 * len, "data") + && pp.field("next") + && TextChunkRef{n}.print_skip(pp, cs) + && pp.close(); + } + case text_chunk_empty: + return pp.cons("text_chunk_empty") + && m_ == 0; + } + return pp.fail("unknown constructor for TextChunks"); +} + + +// +// code for type `Text` +// + +int Text::check_tag(const vm::CellSlice& cs) const { + return text; +} + +bool Text::skip(vm::CellSlice& cs) const { + int chunks; + return cs.fetch_uint_to(8, chunks) + && TextChunks{chunks}.skip(cs); +} + +bool Text::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + int chunks; + return cs.fetch_uint_to(8, chunks) + && TextChunks{chunks}.validate_skip(ops, cs, weak); +} + +bool Text::unpack(vm::CellSlice& cs, Text::Record& data) const { + return cs.fetch_uint_to(8, data.chunks) + && TextChunks{data.chunks}.fetch_to(cs, data.rest); +} + +bool Text::unpack_text(vm::CellSlice& cs, int& chunks, Ref& rest) const { + return cs.fetch_uint_to(8, chunks) + && TextChunks{chunks}.fetch_to(cs, rest); +} + +bool Text::cell_unpack(Ref cell_ref, Text::Record& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool Text::cell_unpack_text(Ref cell_ref, int& chunks, Ref& rest) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_text(cs, chunks, rest) && cs.empty_ext(); +} + +bool Text::pack(vm::CellBuilder& cb, const Text::Record& data) const { + return cb.store_ulong_rchk_bool(data.chunks, 8) + && TextChunks{data.chunks}.store_from(cb, data.rest); +} + +bool Text::pack_text(vm::CellBuilder& cb, int chunks, Ref rest) const { + return cb.store_ulong_rchk_bool(chunks, 8) + && TextChunks{chunks}.store_from(cb, rest); +} + +bool Text::cell_pack(Ref& cell_ref, const Text::Record& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool Text::cell_pack_text(Ref& cell_ref, int chunks, Ref rest) const { + vm::CellBuilder cb; + return pack_text(cb, chunks, std::move(rest)) && std::move(cb).finalize_to(cell_ref); +} + +bool Text::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const { + int chunks; + return pp.open("text") + && cs.fetch_uint_to(8, chunks) + && pp.field_int(chunks, "chunks") + && pp.field("rest") + && TextChunks{chunks}.print_skip(pp, cs) + && pp.close(); +} + +const Text t_Text; + +// +// code for type `ProtoList` +// + +int ProtoList::check_tag(const vm::CellSlice& cs) const { + switch (get_tag(cs)) { + case proto_list_nil: + return cs.have(1) ? proto_list_nil : -1; + case proto_list_next: + return cs.have(1) ? proto_list_next : -1; + } + return -1; +} + +bool ProtoList::skip(vm::CellSlice& cs) const { + switch (get_tag(cs)) { + case proto_list_nil: + return cs.advance(1); + case proto_list_next: + return cs.advance(17) + && skip(cs); + } + return false; +} + +bool ProtoList::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + switch (get_tag(cs)) { + case proto_list_nil: + return cs.advance(1); + case proto_list_next: + return cs.advance(1) + && t_Protocol.validate_skip(ops, cs, weak) + && validate_skip(ops, cs, weak); + } + return false; +} + +bool ProtoList::unpack(vm::CellSlice& cs, ProtoList::Record_proto_list_nil& data) const { + return cs.fetch_ulong(1) == 0; +} + +bool ProtoList::unpack_proto_list_nil(vm::CellSlice& cs) const { + return cs.fetch_ulong(1) == 0; +} + +bool ProtoList::cell_unpack(Ref cell_ref, ProtoList::Record_proto_list_nil& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool ProtoList::cell_unpack_proto_list_nil(Ref cell_ref) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_proto_list_nil(cs) && cs.empty_ext(); +} + +bool ProtoList::unpack(vm::CellSlice& cs, ProtoList::Record_proto_list_next& data) const { + return cs.fetch_ulong(1) == 1 + && t_Protocol.fetch_enum_to(cs, data.head) + && fetch_to(cs, data.tail); +} + +bool ProtoList::unpack_proto_list_next(vm::CellSlice& cs, char& head, Ref& tail) const { + return cs.fetch_ulong(1) == 1 + && t_Protocol.fetch_enum_to(cs, head) + && fetch_to(cs, tail); +} + +bool ProtoList::cell_unpack(Ref cell_ref, ProtoList::Record_proto_list_next& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool ProtoList::cell_unpack_proto_list_next(Ref cell_ref, char& head, Ref& tail) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_proto_list_next(cs, head, tail) && cs.empty_ext(); +} + +bool ProtoList::pack(vm::CellBuilder& cb, const ProtoList::Record_proto_list_nil& data) const { + return cb.store_long_bool(0, 1); +} + +bool ProtoList::pack_proto_list_nil(vm::CellBuilder& cb) const { + return cb.store_long_bool(0, 1); +} + +bool ProtoList::cell_pack(Ref& cell_ref, const ProtoList::Record_proto_list_nil& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool ProtoList::cell_pack_proto_list_nil(Ref& cell_ref) const { + vm::CellBuilder cb; + return pack_proto_list_nil(cb) && std::move(cb).finalize_to(cell_ref); +} + +bool ProtoList::pack(vm::CellBuilder& cb, const ProtoList::Record_proto_list_next& data) const { + return cb.store_long_bool(1, 1) + && t_Protocol.store_enum_from(cb, data.head) + && store_from(cb, data.tail); +} + +bool ProtoList::pack_proto_list_next(vm::CellBuilder& cb, char head, Ref tail) const { + return cb.store_long_bool(1, 1) + && t_Protocol.store_enum_from(cb, head) + && store_from(cb, tail); +} + +bool ProtoList::cell_pack(Ref& cell_ref, const ProtoList::Record_proto_list_next& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool ProtoList::cell_pack_proto_list_next(Ref& cell_ref, char head, Ref tail) const { + vm::CellBuilder cb; + return pack_proto_list_next(cb, head, std::move(tail)) && std::move(cb).finalize_to(cell_ref); +} + +bool ProtoList::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const { + switch (get_tag(cs)) { + case proto_list_nil: + return cs.advance(1) + && pp.cons("proto_list_nil"); + case proto_list_next: + return cs.advance(1) + && pp.open("proto_list_next") + && pp.field("head") + && t_Protocol.print_skip(pp, cs) + && pp.field("tail") + && print_skip(pp, cs) + && pp.close(); + } + return pp.fail("unknown constructor for ProtoList"); +} + +const ProtoList t_ProtoList; + +// +// code for type `Protocol` +// +constexpr unsigned short Protocol::cons_tag[1]; + +int Protocol::check_tag(const vm::CellSlice& cs) const { + return cs.prefetch_ulong(16) == 0x4854 ? proto_http : -1; +} + +bool Protocol::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return cs.fetch_ulong(16) == 0x4854; +} + +bool Protocol::fetch_enum_to(vm::CellSlice& cs, char& value) const { + value = (cs.fetch_ulong(16) == 0x4854) ? 0 : -1; + return !value; +} + +bool Protocol::store_enum_from(vm::CellBuilder& cb, int value) const { + return !value && cb.store_long_bool(0x4854, 16); +} + +bool Protocol::unpack(vm::CellSlice& cs, Protocol::Record& data) const { + return cs.fetch_ulong(16) == 0x4854; +} + +bool Protocol::unpack_proto_http(vm::CellSlice& cs) const { + return cs.fetch_ulong(16) == 0x4854; +} + +bool Protocol::cell_unpack(Ref cell_ref, Protocol::Record& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool Protocol::cell_unpack_proto_http(Ref cell_ref) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_proto_http(cs) && cs.empty_ext(); +} + +bool Protocol::pack(vm::CellBuilder& cb, const Protocol::Record& data) const { + return cb.store_long_bool(0x4854, 16); +} + +bool Protocol::pack_proto_http(vm::CellBuilder& cb) const { + return cb.store_long_bool(0x4854, 16); +} + +bool Protocol::cell_pack(Ref& cell_ref, const Protocol::Record& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool Protocol::cell_pack_proto_http(Ref& cell_ref) const { + vm::CellBuilder cb; + return pack_proto_http(cb) && std::move(cb).finalize_to(cell_ref); +} + +bool Protocol::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const { + return cs.fetch_ulong(16) == 0x4854 + && pp.cons("proto_http"); +} + +const Protocol t_Protocol; + +// +// code for type `DNSRecord` +// +constexpr unsigned short DNSRecord::cons_tag[4]; + +int DNSRecord::check_tag(const vm::CellSlice& cs) const { + switch (get_tag(cs)) { + case dns_text: + return cs.prefetch_ulong(16) == 0x1eda ? dns_text : -1; + case dns_next_resolver: + return cs.prefetch_ulong(16) == 0xba93 ? dns_next_resolver : -1; + case dns_adnl_address: + return cs.prefetch_ulong(16) == 0xad01 ? dns_adnl_address : -1; + case dns_smc_address: + return cs.prefetch_ulong(16) == 0x9fd3 ? dns_smc_address : -1; + } + return -1; +} + +bool DNSRecord::skip(vm::CellSlice& cs) const { + switch (get_tag(cs)) { + case dns_text: + return cs.advance(16) + && t_Text.skip(cs); + case dns_next_resolver: + return cs.advance(16) + && t_MsgAddressInt.skip(cs); + case dns_adnl_address: { + int flags; + return cs.advance(272) + && cs.fetch_uint_to(8, flags) + && flags <= 1 + && (!(flags & 1) || t_ProtoList.skip(cs)); + } + case dns_smc_address: { + int flags; + return cs.advance(16) + && t_MsgAddressInt.skip(cs) + && cs.fetch_uint_to(8, flags) + && flags <= 1 + && (!(flags & 1) || t_SmcCapList.skip(cs)); + } + } + return false; +} + +bool DNSRecord::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + switch (get_tag(cs)) { + case dns_text: + return cs.fetch_ulong(16) == 0x1eda + && t_Text.validate_skip(ops, cs, weak); + case dns_next_resolver: + return cs.fetch_ulong(16) == 0xba93 + && t_MsgAddressInt.validate_skip(ops, cs, weak); + case dns_adnl_address: { + int flags; + return cs.fetch_ulong(16) == 0xad01 + && cs.advance(256) + && cs.fetch_uint_to(8, flags) + && flags <= 1 + && (!(flags & 1) || t_ProtoList.validate_skip(ops, cs, weak)); + } + case dns_smc_address: { + int flags; + return cs.fetch_ulong(16) == 0x9fd3 + && t_MsgAddressInt.validate_skip(ops, cs, weak) + && cs.fetch_uint_to(8, flags) + && flags <= 1 + && (!(flags & 1) || t_SmcCapList.validate_skip(ops, cs, weak)); + } + } + return false; +} + +bool DNSRecord::unpack(vm::CellSlice& cs, DNSRecord::Record_dns_text& data) const { + return cs.fetch_ulong(16) == 0x1eda + && t_Text.fetch_to(cs, data.x); +} + +bool DNSRecord::unpack_dns_text(vm::CellSlice& cs, Ref& x) const { + return cs.fetch_ulong(16) == 0x1eda + && t_Text.fetch_to(cs, x); +} + +bool DNSRecord::cell_unpack(Ref cell_ref, DNSRecord::Record_dns_text& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool DNSRecord::cell_unpack_dns_text(Ref cell_ref, Ref& x) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_dns_text(cs, x) && cs.empty_ext(); +} + +bool DNSRecord::unpack(vm::CellSlice& cs, DNSRecord::Record_dns_next_resolver& data) const { + return cs.fetch_ulong(16) == 0xba93 + && t_MsgAddressInt.fetch_to(cs, data.resolver); +} + +bool DNSRecord::unpack_dns_next_resolver(vm::CellSlice& cs, Ref& resolver) const { + return cs.fetch_ulong(16) == 0xba93 + && t_MsgAddressInt.fetch_to(cs, resolver); +} + +bool DNSRecord::cell_unpack(Ref cell_ref, DNSRecord::Record_dns_next_resolver& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool DNSRecord::cell_unpack_dns_next_resolver(Ref cell_ref, Ref& resolver) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_dns_next_resolver(cs, resolver) && cs.empty_ext(); +} + +bool DNSRecord::unpack(vm::CellSlice& cs, DNSRecord::Record_dns_adnl_address& data) const { + return cs.fetch_ulong(16) == 0xad01 + && cs.fetch_bits_to(data.adnl_addr.bits(), 256) + && cs.fetch_uint_to(8, data.flags) + && data.flags <= 1 + && (!(data.flags & 1) || t_ProtoList.fetch_to(cs, data.proto_list)); +} + +bool DNSRecord::unpack_dns_adnl_address(vm::CellSlice& cs, td::BitArray<256>& adnl_addr, int& flags, Ref& proto_list) const { + return cs.fetch_ulong(16) == 0xad01 + && cs.fetch_bits_to(adnl_addr.bits(), 256) + && cs.fetch_uint_to(8, flags) + && flags <= 1 + && (!(flags & 1) || t_ProtoList.fetch_to(cs, proto_list)); +} + +bool DNSRecord::cell_unpack(Ref cell_ref, DNSRecord::Record_dns_adnl_address& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool DNSRecord::cell_unpack_dns_adnl_address(Ref cell_ref, td::BitArray<256>& adnl_addr, int& flags, Ref& proto_list) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_dns_adnl_address(cs, adnl_addr, flags, proto_list) && cs.empty_ext(); +} + +bool DNSRecord::unpack(vm::CellSlice& cs, DNSRecord::Record_dns_smc_address& data) const { + return cs.fetch_ulong(16) == 0x9fd3 + && t_MsgAddressInt.fetch_to(cs, data.smc_addr) + && cs.fetch_uint_to(8, data.flags) + && data.flags <= 1 + && (!(data.flags & 1) || t_SmcCapList.fetch_to(cs, data.cap_list)); +} + +bool DNSRecord::unpack_dns_smc_address(vm::CellSlice& cs, Ref& smc_addr, int& flags, Ref& cap_list) const { + return cs.fetch_ulong(16) == 0x9fd3 + && t_MsgAddressInt.fetch_to(cs, smc_addr) + && cs.fetch_uint_to(8, flags) + && flags <= 1 + && (!(flags & 1) || t_SmcCapList.fetch_to(cs, cap_list)); +} + +bool DNSRecord::cell_unpack(Ref cell_ref, DNSRecord::Record_dns_smc_address& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool DNSRecord::cell_unpack_dns_smc_address(Ref cell_ref, Ref& smc_addr, int& flags, Ref& cap_list) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_dns_smc_address(cs, smc_addr, flags, cap_list) && cs.empty_ext(); +} + +bool DNSRecord::pack(vm::CellBuilder& cb, const DNSRecord::Record_dns_text& data) const { + return cb.store_long_bool(0x1eda, 16) + && t_Text.store_from(cb, data.x); +} + +bool DNSRecord::pack_dns_text(vm::CellBuilder& cb, Ref x) const { + return cb.store_long_bool(0x1eda, 16) + && t_Text.store_from(cb, x); +} + +bool DNSRecord::cell_pack(Ref& cell_ref, const DNSRecord::Record_dns_text& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool DNSRecord::cell_pack_dns_text(Ref& cell_ref, Ref x) const { + vm::CellBuilder cb; + return pack_dns_text(cb, std::move(x)) && std::move(cb).finalize_to(cell_ref); +} + +bool DNSRecord::pack(vm::CellBuilder& cb, const DNSRecord::Record_dns_next_resolver& data) const { + return cb.store_long_bool(0xba93, 16) + && t_MsgAddressInt.store_from(cb, data.resolver); +} + +bool DNSRecord::pack_dns_next_resolver(vm::CellBuilder& cb, Ref resolver) const { + return cb.store_long_bool(0xba93, 16) + && t_MsgAddressInt.store_from(cb, resolver); +} + +bool DNSRecord::cell_pack(Ref& cell_ref, const DNSRecord::Record_dns_next_resolver& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool DNSRecord::cell_pack_dns_next_resolver(Ref& cell_ref, Ref resolver) const { + vm::CellBuilder cb; + return pack_dns_next_resolver(cb, std::move(resolver)) && std::move(cb).finalize_to(cell_ref); +} + +bool DNSRecord::pack(vm::CellBuilder& cb, const DNSRecord::Record_dns_adnl_address& data) const { + return cb.store_long_bool(0xad01, 16) + && cb.store_bits_bool(data.adnl_addr.cbits(), 256) + && cb.store_ulong_rchk_bool(data.flags, 8) + && data.flags <= 1 + && (!(data.flags & 1) || t_ProtoList.store_from(cb, data.proto_list)); +} + +bool DNSRecord::pack_dns_adnl_address(vm::CellBuilder& cb, td::BitArray<256> adnl_addr, int flags, Ref proto_list) const { + return cb.store_long_bool(0xad01, 16) + && cb.store_bits_bool(adnl_addr.cbits(), 256) + && cb.store_ulong_rchk_bool(flags, 8) + && flags <= 1 + && (!(flags & 1) || t_ProtoList.store_from(cb, proto_list)); +} + +bool DNSRecord::cell_pack(Ref& cell_ref, const DNSRecord::Record_dns_adnl_address& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool DNSRecord::cell_pack_dns_adnl_address(Ref& cell_ref, td::BitArray<256> adnl_addr, int flags, Ref proto_list) const { + vm::CellBuilder cb; + return pack_dns_adnl_address(cb, adnl_addr, flags, std::move(proto_list)) && std::move(cb).finalize_to(cell_ref); +} + +bool DNSRecord::pack(vm::CellBuilder& cb, const DNSRecord::Record_dns_smc_address& data) const { + return cb.store_long_bool(0x9fd3, 16) + && t_MsgAddressInt.store_from(cb, data.smc_addr) + && cb.store_ulong_rchk_bool(data.flags, 8) + && data.flags <= 1 + && (!(data.flags & 1) || t_SmcCapList.store_from(cb, data.cap_list)); +} + +bool DNSRecord::pack_dns_smc_address(vm::CellBuilder& cb, Ref smc_addr, int flags, Ref cap_list) const { + return cb.store_long_bool(0x9fd3, 16) + && t_MsgAddressInt.store_from(cb, smc_addr) + && cb.store_ulong_rchk_bool(flags, 8) + && flags <= 1 + && (!(flags & 1) || t_SmcCapList.store_from(cb, cap_list)); +} + +bool DNSRecord::cell_pack(Ref& cell_ref, const DNSRecord::Record_dns_smc_address& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool DNSRecord::cell_pack_dns_smc_address(Ref& cell_ref, Ref smc_addr, int flags, Ref cap_list) const { + vm::CellBuilder cb; + return pack_dns_smc_address(cb, std::move(smc_addr), flags, std::move(cap_list)) && std::move(cb).finalize_to(cell_ref); +} + +bool DNSRecord::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const { + switch (get_tag(cs)) { + case dns_text: + return cs.fetch_ulong(16) == 0x1eda + && pp.open("dns_text") + && pp.field() + && t_Text.print_skip(pp, cs) + && pp.close(); + case dns_next_resolver: + return cs.fetch_ulong(16) == 0xba93 + && pp.open("dns_next_resolver") + && pp.field("resolver") + && t_MsgAddressInt.print_skip(pp, cs) + && pp.close(); + case dns_adnl_address: { + int flags; + return cs.fetch_ulong(16) == 0xad01 + && pp.open("dns_adnl_address") + && pp.fetch_bits_field(cs, 256, "adnl_addr") + && cs.fetch_uint_to(8, flags) + && pp.field_int(flags, "flags") + && flags <= 1 + && (!(flags & 1) || (pp.field("proto_list") && t_ProtoList.print_skip(pp, cs))) + && pp.close(); + } + case dns_smc_address: { + int flags; + return cs.fetch_ulong(16) == 0x9fd3 + && pp.open("dns_smc_address") + && pp.field("smc_addr") + && t_MsgAddressInt.print_skip(pp, cs) + && cs.fetch_uint_to(8, flags) + && pp.field_int(flags, "flags") + && flags <= 1 + && (!(flags & 1) || (pp.field("cap_list") && t_SmcCapList.print_skip(pp, cs))) + && pp.close(); + } + } + return pp.fail("unknown constructor for DNSRecord"); +} + +const DNSRecord t_DNSRecord; + +// +// code for type `SmcCapList` +// + +int SmcCapList::check_tag(const vm::CellSlice& cs) const { + switch (get_tag(cs)) { + case cap_list_nil: + return cs.have(1) ? cap_list_nil : -1; + case cap_list_next: + return cs.have(1) ? cap_list_next : -1; + } + return -1; +} + +bool SmcCapList::skip(vm::CellSlice& cs) const { + switch (get_tag(cs)) { + case cap_list_nil: + return cs.advance(1); + case cap_list_next: + return cs.advance(1) + && t_SmcCapability.skip(cs) + && skip(cs); + } + return false; +} + +bool SmcCapList::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + switch (get_tag(cs)) { + case cap_list_nil: + return cs.advance(1); + case cap_list_next: + return cs.advance(1) + && t_SmcCapability.validate_skip(ops, cs, weak) + && validate_skip(ops, cs, weak); + } + return false; +} + +bool SmcCapList::unpack(vm::CellSlice& cs, SmcCapList::Record_cap_list_nil& data) const { + return cs.fetch_ulong(1) == 0; +} + +bool SmcCapList::unpack_cap_list_nil(vm::CellSlice& cs) const { + return cs.fetch_ulong(1) == 0; +} + +bool SmcCapList::cell_unpack(Ref cell_ref, SmcCapList::Record_cap_list_nil& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool SmcCapList::cell_unpack_cap_list_nil(Ref cell_ref) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_cap_list_nil(cs) && cs.empty_ext(); +} + +bool SmcCapList::unpack(vm::CellSlice& cs, SmcCapList::Record_cap_list_next& data) const { + return cs.fetch_ulong(1) == 1 + && t_SmcCapability.fetch_to(cs, data.head) + && fetch_to(cs, data.tail); +} + +bool SmcCapList::unpack_cap_list_next(vm::CellSlice& cs, Ref& head, Ref& tail) const { + return cs.fetch_ulong(1) == 1 + && t_SmcCapability.fetch_to(cs, head) + && fetch_to(cs, tail); +} + +bool SmcCapList::cell_unpack(Ref cell_ref, SmcCapList::Record_cap_list_next& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool SmcCapList::cell_unpack_cap_list_next(Ref cell_ref, Ref& head, Ref& tail) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_cap_list_next(cs, head, tail) && cs.empty_ext(); +} + +bool SmcCapList::pack(vm::CellBuilder& cb, const SmcCapList::Record_cap_list_nil& data) const { + return cb.store_long_bool(0, 1); +} + +bool SmcCapList::pack_cap_list_nil(vm::CellBuilder& cb) const { + return cb.store_long_bool(0, 1); +} + +bool SmcCapList::cell_pack(Ref& cell_ref, const SmcCapList::Record_cap_list_nil& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool SmcCapList::cell_pack_cap_list_nil(Ref& cell_ref) const { + vm::CellBuilder cb; + return pack_cap_list_nil(cb) && std::move(cb).finalize_to(cell_ref); +} + +bool SmcCapList::pack(vm::CellBuilder& cb, const SmcCapList::Record_cap_list_next& data) const { + return cb.store_long_bool(1, 1) + && t_SmcCapability.store_from(cb, data.head) + && store_from(cb, data.tail); +} + +bool SmcCapList::pack_cap_list_next(vm::CellBuilder& cb, Ref head, Ref tail) const { + return cb.store_long_bool(1, 1) + && t_SmcCapability.store_from(cb, head) + && store_from(cb, tail); +} + +bool SmcCapList::cell_pack(Ref& cell_ref, const SmcCapList::Record_cap_list_next& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool SmcCapList::cell_pack_cap_list_next(Ref& cell_ref, Ref head, Ref tail) const { + vm::CellBuilder cb; + return pack_cap_list_next(cb, std::move(head), std::move(tail)) && std::move(cb).finalize_to(cell_ref); +} + +bool SmcCapList::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const { + switch (get_tag(cs)) { + case cap_list_nil: + return cs.advance(1) + && pp.cons("cap_list_nil"); + case cap_list_next: + return cs.advance(1) + && pp.open("cap_list_next") + && pp.field("head") + && t_SmcCapability.print_skip(pp, cs) + && pp.field("tail") + && print_skip(pp, cs) + && pp.close(); + } + return pp.fail("unknown constructor for SmcCapList"); +} + +const SmcCapList t_SmcCapList; + +// +// code for type `SmcCapability` +// +constexpr char SmcCapability::cons_len[4]; +constexpr unsigned short SmcCapability::cons_tag[4]; + +int SmcCapability::check_tag(const vm::CellSlice& cs) const { + switch (get_tag(cs)) { + case cap_method_seqno: + return cs.prefetch_ulong(16) == 0x5371 ? cap_method_seqno : -1; + case cap_method_pubkey: + return cs.prefetch_ulong(16) == 0x71f4 ? cap_method_pubkey : -1; + case cap_is_wallet: + return cs.prefetch_ulong(16) == 0x2177 ? cap_is_wallet : -1; + case cap_name: + return cs.prefetch_ulong(8) == 0xff ? cap_name : -1; + } + return -1; +} + +bool SmcCapability::skip(vm::CellSlice& cs) const { + switch (get_tag(cs)) { + case cap_method_seqno: + return cs.advance(16); + case cap_method_pubkey: + return cs.advance(16); + case cap_is_wallet: + return cs.advance(16); + case cap_name: + return cs.advance(8) + && t_Text.skip(cs); + } + return false; +} + +bool SmcCapability::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + switch (get_tag(cs)) { + case cap_method_seqno: + return cs.fetch_ulong(16) == 0x5371; + case cap_method_pubkey: + return cs.fetch_ulong(16) == 0x71f4; + case cap_is_wallet: + return cs.fetch_ulong(16) == 0x2177; + case cap_name: + return cs.fetch_ulong(8) == 0xff + && t_Text.validate_skip(ops, cs, weak); + } + return false; +} + +bool SmcCapability::unpack(vm::CellSlice& cs, SmcCapability::Record_cap_method_seqno& data) const { + return cs.fetch_ulong(16) == 0x5371; +} + +bool SmcCapability::unpack_cap_method_seqno(vm::CellSlice& cs) const { + return cs.fetch_ulong(16) == 0x5371; +} + +bool SmcCapability::cell_unpack(Ref cell_ref, SmcCapability::Record_cap_method_seqno& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool SmcCapability::cell_unpack_cap_method_seqno(Ref cell_ref) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_cap_method_seqno(cs) && cs.empty_ext(); +} + +bool SmcCapability::unpack(vm::CellSlice& cs, SmcCapability::Record_cap_method_pubkey& data) const { + return cs.fetch_ulong(16) == 0x71f4; +} + +bool SmcCapability::unpack_cap_method_pubkey(vm::CellSlice& cs) const { + return cs.fetch_ulong(16) == 0x71f4; +} + +bool SmcCapability::cell_unpack(Ref cell_ref, SmcCapability::Record_cap_method_pubkey& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool SmcCapability::cell_unpack_cap_method_pubkey(Ref cell_ref) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_cap_method_pubkey(cs) && cs.empty_ext(); +} + +bool SmcCapability::unpack(vm::CellSlice& cs, SmcCapability::Record_cap_is_wallet& data) const { + return cs.fetch_ulong(16) == 0x2177; +} + +bool SmcCapability::unpack_cap_is_wallet(vm::CellSlice& cs) const { + return cs.fetch_ulong(16) == 0x2177; +} + +bool SmcCapability::cell_unpack(Ref cell_ref, SmcCapability::Record_cap_is_wallet& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool SmcCapability::cell_unpack_cap_is_wallet(Ref cell_ref) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_cap_is_wallet(cs) && cs.empty_ext(); +} + +bool SmcCapability::unpack(vm::CellSlice& cs, SmcCapability::Record_cap_name& data) const { + return cs.fetch_ulong(8) == 0xff + && t_Text.fetch_to(cs, data.name); +} + +bool SmcCapability::unpack_cap_name(vm::CellSlice& cs, Ref& name) const { + return cs.fetch_ulong(8) == 0xff + && t_Text.fetch_to(cs, name); +} + +bool SmcCapability::cell_unpack(Ref cell_ref, SmcCapability::Record_cap_name& data) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack(cs, data) && cs.empty_ext(); +} + +bool SmcCapability::cell_unpack_cap_name(Ref cell_ref, Ref& name) const { + if (cell_ref.is_null()) { return false; } + auto cs = load_cell_slice(std::move(cell_ref)); + return unpack_cap_name(cs, name) && cs.empty_ext(); +} + +bool SmcCapability::pack(vm::CellBuilder& cb, const SmcCapability::Record_cap_method_seqno& data) const { + return cb.store_long_bool(0x5371, 16); +} + +bool SmcCapability::pack_cap_method_seqno(vm::CellBuilder& cb) const { + return cb.store_long_bool(0x5371, 16); +} + +bool SmcCapability::cell_pack(Ref& cell_ref, const SmcCapability::Record_cap_method_seqno& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool SmcCapability::cell_pack_cap_method_seqno(Ref& cell_ref) const { + vm::CellBuilder cb; + return pack_cap_method_seqno(cb) && std::move(cb).finalize_to(cell_ref); +} + +bool SmcCapability::pack(vm::CellBuilder& cb, const SmcCapability::Record_cap_method_pubkey& data) const { + return cb.store_long_bool(0x71f4, 16); +} + +bool SmcCapability::pack_cap_method_pubkey(vm::CellBuilder& cb) const { + return cb.store_long_bool(0x71f4, 16); +} + +bool SmcCapability::cell_pack(Ref& cell_ref, const SmcCapability::Record_cap_method_pubkey& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool SmcCapability::cell_pack_cap_method_pubkey(Ref& cell_ref) const { + vm::CellBuilder cb; + return pack_cap_method_pubkey(cb) && std::move(cb).finalize_to(cell_ref); +} + +bool SmcCapability::pack(vm::CellBuilder& cb, const SmcCapability::Record_cap_is_wallet& data) const { + return cb.store_long_bool(0x2177, 16); +} + +bool SmcCapability::pack_cap_is_wallet(vm::CellBuilder& cb) const { + return cb.store_long_bool(0x2177, 16); +} + +bool SmcCapability::cell_pack(Ref& cell_ref, const SmcCapability::Record_cap_is_wallet& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool SmcCapability::cell_pack_cap_is_wallet(Ref& cell_ref) const { + vm::CellBuilder cb; + return pack_cap_is_wallet(cb) && std::move(cb).finalize_to(cell_ref); +} + +bool SmcCapability::pack(vm::CellBuilder& cb, const SmcCapability::Record_cap_name& data) const { + return cb.store_long_bool(0xff, 8) + && t_Text.store_from(cb, data.name); +} + +bool SmcCapability::pack_cap_name(vm::CellBuilder& cb, Ref name) const { + return cb.store_long_bool(0xff, 8) + && t_Text.store_from(cb, name); +} + +bool SmcCapability::cell_pack(Ref& cell_ref, const SmcCapability::Record_cap_name& data) const { + vm::CellBuilder cb; + return pack(cb, data) && std::move(cb).finalize_to(cell_ref); +} + +bool SmcCapability::cell_pack_cap_name(Ref& cell_ref, Ref name) const { + vm::CellBuilder cb; + return pack_cap_name(cb, std::move(name)) && std::move(cb).finalize_to(cell_ref); +} + +bool SmcCapability::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const { + switch (get_tag(cs)) { + case cap_method_seqno: + return cs.fetch_ulong(16) == 0x5371 + && pp.cons("cap_method_seqno"); + case cap_method_pubkey: + return cs.fetch_ulong(16) == 0x71f4 + && pp.cons("cap_method_pubkey"); + case cap_is_wallet: + return cs.fetch_ulong(16) == 0x2177 + && pp.cons("cap_is_wallet"); + case cap_name: + return cs.fetch_ulong(8) == 0xff + && pp.open("cap_name") + && pp.field("name") + && t_Text.print_skip(pp, cs) + && pp.close(); + } + return pp.fail("unknown constructor for SmcCapability"); +} + +const SmcCapability t_SmcCapability; + // definitions of constant types used const NatWidth t_natwidth_1{1}; @@ -17368,12 +21103,13 @@ const NatWidth t_natwidth_6{6}; const NatWidth t_natwidth_8{8}; const MessageRelaxed t_MessageRelaxed_Any{t_Anything}; const RefT t_Ref_MessageRelaxed_Any{t_MessageRelaxed_Any}; +const NatWidth t_natwidth_7{7}; const NatLeq t_natleq_60{60}; const RefT t_Ref_OutMsgQueueInfo{t_OutMsgQueueInfo}; const RefT t_Ref_ShardAccounts{t_ShardAccounts}; const HashmapE t_HashmapE_256_LibDescr{256, t_LibDescr}; const Maybe t_Maybe_BlkMasterInfo{t_BlkMasterInfo}; -const RefT t_Ref_TYPE_1637{t_ShardStateUnsplit_aux}; +const RefT t_Ref_TYPE_1638{t_ShardStateUnsplit_aux}; const RefT t_Ref_McStateExtra{t_McStateExtra}; const Maybe t_Maybe_Ref_McStateExtra{t_Ref_McStateExtra}; const RefT t_Ref_ShardStateUnsplit{t_ShardStateUnsplit}; @@ -17392,8 +21128,8 @@ const RefT t_Ref_OutMsgDescr{t_OutMsgDescr}; const RefT t_Ref_ShardAccountBlocks{t_ShardAccountBlocks}; const RefT t_Ref_McBlockExtra{t_McBlockExtra}; const Maybe t_Maybe_Ref_McBlockExtra{t_Ref_McBlockExtra}; -const RefT t_Ref_TYPE_1647{t_ValueFlow_aux}; -const RefT t_Ref_TYPE_1648{t_ValueFlow_aux1}; +const RefT t_Ref_TYPE_1648{t_ValueFlow_aux}; +const RefT t_Ref_TYPE_1649{t_ValueFlow_aux1}; const NatWidth t_natwidth_3{3}; const BinTree t_BinTree_ShardDescr{t_ShardDescr}; const RefT t_Ref_BinTree_ShardDescr{t_BinTree_ShardDescr}; @@ -17403,13 +21139,14 @@ const Hashmap t_Hashmap_32_Ref_Cell{32, t_RefCell}; const RefT t_Ref_Hashmap_32_Ref_Cell{t_Hashmap_32_Ref_Cell}; const HashmapAugE t_HashmapAugE_32_KeyExtBlkRef_KeyMaxLt{32, t_KeyExtBlkRef, t_KeyMaxLt}; const HashmapE t_HashmapE_256_CreatorStats{256, t_CreatorStats}; +const HashmapAugE t_HashmapAugE_256_CreatorStats_uint32{256, t_CreatorStats, t_uint32}; const NatWidth t_natwidth_16{16}; const Maybe t_Maybe_ExtBlkRef{t_ExtBlkRef}; -const RefT t_Ref_TYPE_1665{t_McStateExtra_aux}; +const RefT t_Ref_TYPE_1666{t_McStateExtra_aux}; const RefT t_Ref_SignedCertificate{t_SignedCertificate}; const HashmapE t_HashmapE_16_CryptoSignaturePair{16, t_CryptoSignaturePair}; const Maybe t_Maybe_Ref_InMsg{t_Ref_InMsg}; -const RefT t_Ref_TYPE_1673{t_McBlockExtra_aux}; +const RefT t_Ref_TYPE_1674{t_McBlockExtra_aux}; const Hashmap t_Hashmap_16_ValidatorDescr{16, t_ValidatorDescr}; const HashmapE t_HashmapE_16_ValidatorDescr{16, t_ValidatorDescr}; const Hashmap t_Hashmap_32_True{32, t_True}; @@ -17425,6 +21162,156 @@ const RefT t_Ref_BlockSignatures{t_BlockSignatures}; const Maybe t_Maybe_Ref_BlockSignatures{t_Ref_BlockSignatures}; const RefT t_Ref_TopBlockDescr{t_TopBlockDescr}; const HashmapE t_HashmapE_96_Ref_TopBlockDescr{96, t_Ref_TopBlockDescr}; +const Int t_int64{64}; +const Int t_int257{257}; +const NatWidth t_natwidth_10{10}; +const NatLeq t_natleq_4{4}; +const RefT t_Ref_VmStackValue{t_VmStackValue}; +const NatWidth t_natwidth_24{24}; +const HashmapE t_HashmapE_4_VmStackValue{4, t_VmStackValue}; +const RefT t_Ref_TYPE_1705{t_VmGasLimits_aux}; +const HashmapE t_HashmapE_256_Ref_Cell{256, t_RefCell}; +const UInt t_uint13{13}; +const Maybe t_Maybe_uint13{t_uint13}; +const Maybe t_Maybe_VmStack{t_VmStack}; +const Int t_int16{16}; +const Maybe t_Maybe_int16{t_int16}; +const RefT t_Ref_VmCont{t_VmCont}; +const UInt t_uint63{63}; +const RefT t_Ref_DNSRecord{t_DNSRecord}; +const HashmapE t_HashmapE_16_Ref_DNSRecord{16, t_Ref_DNSRecord}; + +// definition of type name registration function +bool register_simple_types(std::function func) { + return func("Unit", &t_Unit) + && func("True", &t_True) + && func("Bool", &t_Bool) + && func("BoolFalse", &t_BoolFalse) + && func("BoolTrue", &t_BoolTrue) + && func("Bit", &t_Bit) + && func("Unary", &t_Unary) + && func("MsgAddressExt", &t_MsgAddressExt) + && func("Anycast", &t_Anycast) + && func("MsgAddressInt", &t_MsgAddressInt) + && func("MsgAddress", &t_MsgAddress) + && func("Grams", &t_Grams) + && func("ExtraCurrencyCollection", &t_ExtraCurrencyCollection) + && func("CurrencyCollection", &t_CurrencyCollection) + && func("CommonMsgInfo", &t_CommonMsgInfo) + && func("CommonMsgInfoRelaxed", &t_CommonMsgInfoRelaxed) + && func("TickTock", &t_TickTock) + && func("SimpleLib", &t_SimpleLib) + && func("StateInit", &t_StateInit) + && func("IntermediateAddress", &t_IntermediateAddress) + && func("MsgEnvelope", &t_MsgEnvelope) + && func("Transaction", &t_Transaction) + && func("InMsg", &t_InMsg) + && func("ImportFees", &t_ImportFees) + && func("InMsgDescr", &t_InMsgDescr) + && func("OutMsg", &t_OutMsg) + && func("EnqueuedMsg", &t_EnqueuedMsg) + && func("OutMsgDescr", &t_OutMsgDescr) + && func("OutMsgQueue", &t_OutMsgQueue) + && func("ProcessedUpto", &t_ProcessedUpto) + && func("ProcessedInfo", &t_ProcessedInfo) + && func("IhrPendingSince", &t_IhrPendingSince) + && func("IhrPendingInfo", &t_IhrPendingInfo) + && func("OutMsgQueueInfo", &t_OutMsgQueueInfo) + && func("StorageUsed", &t_StorageUsed) + && func("StorageUsedShort", &t_StorageUsedShort) + && func("StorageInfo", &t_StorageInfo) + && func("Account", &t_Account) + && func("AccountStorage", &t_AccountStorage) + && func("AccountState", &t_AccountState) + && func("AccountStatus", &t_AccountStatus) + && func("ShardAccount", &t_ShardAccount) + && func("DepthBalanceInfo", &t_DepthBalanceInfo) + && func("ShardAccounts", &t_ShardAccounts) + && func("TransactionDescr", &t_TransactionDescr) + && func("AccountBlock", &t_AccountBlock) + && func("ShardAccountBlocks", &t_ShardAccountBlocks) + && func("AccStatusChange", &t_AccStatusChange) + && func("TrStoragePhase", &t_TrStoragePhase) + && func("TrCreditPhase", &t_TrCreditPhase) + && func("ComputeSkipReason", &t_ComputeSkipReason) + && func("TrComputePhase", &t_TrComputePhase) + && func("TrActionPhase", &t_TrActionPhase) + && func("TrBouncePhase", &t_TrBouncePhase) + && func("SplitMergeInfo", &t_SplitMergeInfo) + && func("SmartContractInfo", &t_SmartContractInfo) + && func("OutAction", &t_OutAction) + && func("LibRef", &t_LibRef) + && func("OutListNode", &t_OutListNode) + && func("ShardIdent", &t_ShardIdent) + && func("ExtBlkRef", &t_ExtBlkRef) + && func("BlockIdExt", &t_BlockIdExt) + && func("BlkMasterInfo", &t_BlkMasterInfo) + && func("LibDescr", &t_LibDescr) + && func("McStateExtra", &t_McStateExtra) + && func("ShardStateUnsplit", &t_ShardStateUnsplit) + && func("ShardState", &t_ShardState) + && func("BlockInfo", &t_BlockInfo) + && func("ValueFlow", &t_ValueFlow) + && func("BlockExtra", &t_BlockExtra) + && func("Block", &t_Block) + && func("McBlockExtra", &t_McBlockExtra) + && func("FutureSplitMerge", &t_FutureSplitMerge) + && func("ShardDescr", &t_ShardDescr) + && func("ShardHashes", &t_ShardHashes) + && func("ShardFeeCreated", &t_ShardFeeCreated) + && func("ShardFees", &t_ShardFees) + && func("ConfigParams", &t_ConfigParams) + && func("ValidatorInfo", &t_ValidatorInfo) + && func("ValidatorBaseInfo", &t_ValidatorBaseInfo) + && func("KeyMaxLt", &t_KeyMaxLt) + && func("KeyExtBlkRef", &t_KeyExtBlkRef) + && func("OldMcBlocksInfo", &t_OldMcBlocksInfo) + && func("Counters", &t_Counters) + && func("CreatorStats", &t_CreatorStats) + && func("BlockCreateStats", &t_BlockCreateStats) + && func("SigPubKey", &t_SigPubKey) + && func("CryptoSignatureSimple", &t_CryptoSignatureSimple) + && func("CryptoSignature", &t_CryptoSignature) + && func("CryptoSignaturePair", &t_CryptoSignaturePair) + && func("Certificate", &t_Certificate) + && func("CertificateEnv", &t_CertificateEnv) + && func("SignedCertificate", &t_SignedCertificate) + && func("ValidatorDescr", &t_ValidatorDescr) + && func("ValidatorSet", &t_ValidatorSet) + && func("GlobalVersion", &t_GlobalVersion) + && func("WorkchainDescr", &t_WorkchainDescr) + && func("BlockCreateFees", &t_BlockCreateFees) + && func("StoragePrices", &t_StoragePrices) + && func("GasLimitsPrices", &t_GasLimitsPrices) + && func("ParamLimits", &t_ParamLimits) + && func("BlockLimits", &t_BlockLimits) + && func("MsgForwardPrices", &t_MsgForwardPrices) + && func("CatchainConfig", &t_CatchainConfig) + && func("ConsensusConfig", &t_ConsensusConfig) + && func("ValidatorTempKey", &t_ValidatorTempKey) + && func("ValidatorSignedTempKey", &t_ValidatorSignedTempKey) + && func("BlockSignaturesPure", &t_BlockSignaturesPure) + && func("BlockSignatures", &t_BlockSignatures) + && func("BlockProof", &t_BlockProof) + && func("TopBlockDescr", &t_TopBlockDescr) + && func("TopBlockDescrSet", &t_TopBlockDescrSet) + && func("VmStackValue", &t_VmStackValue) + && func("VmCellSlice", &t_VmCellSlice) + && func("VmCont", &t_VmCont) + && func("VmStack", &t_VmStack) + && func("VmSaveList", &t_VmSaveList) + && func("VmGasLimits", &t_VmGasLimits) + && func("VmLibraries", &t_VmLibraries) + && func("VmControlData", &t_VmControlData) + && func("DNSRecord", &t_DNSRecord) + && func("DNS_RecordSet", &t_DNS_RecordSet) + && func("Text", &t_Text) + && func("ProtoList", &t_ProtoList) + && func("Protocol", &t_Protocol) + && func("SmcCapList", &t_SmcCapList) + && func("SmcCapability", &t_SmcCapability); +} + } // namespace gen diff --git a/submodules/ton/tonlib-src/crypto/block/block-auto.h b/submodules/ton/tonlib-src/crypto/block/block-auto.h index 507b5161e8..ac0bf542b8 100644 --- a/submodules/ton/tonlib-src/crypto/block/block-auto.h +++ b/submodules/ton/tonlib-src/crypto/block/block-auto.h @@ -15,11 +15,16 @@ // uses built-in type `uint` // uses built-in type `bits` // uses built-in type `int8` +// uses built-in type `uint13` // uses built-in type `uint15` +// uses built-in type `int16` // uses built-in type `uint16` // uses built-in type `int32` // uses built-in type `uint32` +// uses built-in type `uint63` +// uses built-in type `int64` // uses built-in type `uint64` +// uses built-in type `int257` // uses built-in type `bits256` namespace block { @@ -47,7 +52,7 @@ struct Unit final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return true; } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override { + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override { return true; } bool fetch_enum_to(vm::CellSlice& cs, char& value) const; @@ -88,7 +93,7 @@ struct True final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return true; } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override { + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override { return true; } bool fetch_enum_to(vm::CellSlice& cs, char& value) const; @@ -132,7 +137,7 @@ struct Bool final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return cs.advance(1); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override { + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override { return cs.advance(1); } bool fetch_enum_to(vm::CellSlice& cs, char& value) const; @@ -181,7 +186,7 @@ struct BoolFalse final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return cs.advance(1); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool fetch_enum_to(vm::CellSlice& cs, char& value) const; bool store_enum_from(vm::CellBuilder& cb, int value) const; bool unpack(vm::CellSlice& cs, Record& data) const; @@ -221,7 +226,7 @@ struct BoolTrue final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return cs.advance(1); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool fetch_enum_to(vm::CellSlice& cs, char& value) const; bool store_enum_from(vm::CellBuilder& cb, int value) const; bool unpack(vm::CellSlice& cs, Record& data) const; @@ -263,7 +268,7 @@ struct Maybe final : TLB_Complex { Record_just(Ref _value) : value(std::move(_value)) {} }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record_nothing& data) const; bool unpack_nothing(vm::CellSlice& cs) const; bool cell_unpack(Ref cell_ref, Record_nothing& data) const; @@ -312,7 +317,7 @@ struct Either final : TLB_Complex { Record_right(Ref _value) : value(std::move(_value)) {} }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record_left& data) const; bool unpack_left(vm::CellSlice& cs, Ref& value) const; bool cell_unpack(Ref cell_ref, Record_left& data) const; @@ -356,7 +361,7 @@ struct Both final : TLB_Complex { Record(Ref _first, Ref _second) : first(std::move(_first)), second(std::move(_second)) {} }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_pair(vm::CellSlice& cs, Ref& first, Ref& second) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -394,7 +399,7 @@ struct Bit final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return cs.advance(1); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override { + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override { return cs.advance(1); } bool unpack(vm::CellSlice& cs, Record& data) const; @@ -429,7 +434,7 @@ struct Hashmap final : TLB_Complex { Hashmap(int m, const TLB& X) : m_(m), X_(X) {} struct Record; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool cell_unpack(Ref cell_ref, Record& data) const; bool pack(vm::CellBuilder& cb, const Record& data) const; @@ -473,7 +478,7 @@ struct HashmapNode final : TLB_Complex { }; struct Record_hmn_fork; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record_hmn_leaf& data) const; bool unpack_hmn_leaf(vm::CellSlice& cs, Ref& value) const; bool cell_unpack(Ref cell_ref, Record_hmn_leaf& data) const; @@ -522,8 +527,8 @@ struct HmLabel final : TLB_Complex { struct Record_hml_same; bool skip(vm::CellSlice& cs) const override; bool skip(vm::CellSlice& cs, int& m_) const; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; - bool validate_skip(vm::CellSlice& cs, bool weak, int& m_) const; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int *ops, vm::CellSlice& cs, bool weak, int& m_) const; bool fetch_to(vm::CellSlice& cs, Ref& res, int& m_) const; bool unpack(vm::CellSlice& cs, Record_hml_short& data, int& m_) const; bool cell_unpack(Ref cell_ref, Record_hml_short& data, int& m_) const; @@ -603,8 +608,8 @@ struct Unary final : TLB_Complex { }; bool skip(vm::CellSlice& cs) const override; bool skip(vm::CellSlice& cs, int& m_) const; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; - bool validate_skip(vm::CellSlice& cs, bool weak, int& m_) const; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int *ops, vm::CellSlice& cs, bool weak, int& m_) const; bool fetch_to(vm::CellSlice& cs, Ref& res, int& m_) const; bool unpack(vm::CellSlice& cs, Record_unary_zero& data, int& m_) const; bool unpack_unary_zero(vm::CellSlice& cs, int& m_) const; @@ -656,7 +661,7 @@ struct HashmapE final : TLB_Complex { Record_hme_root(Ref _root) : n(-1), root(std::move(_root)) {} }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record_hme_empty& data) const; bool unpack_hme_empty(vm::CellSlice& cs) const; bool cell_unpack(Ref cell_ref, Record_hme_empty& data) const; @@ -700,7 +705,7 @@ struct BitstringSet final : TLB_Complex { Record(Ref _x) : n(-1), x(std::move(_x)) {} }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_cons1(vm::CellSlice& cs, int& n, Ref& x) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -731,7 +736,7 @@ struct HashmapAug final : TLB_Complex { HashmapAug(int m, const TLB& X, const TLB& Y) : m_(m), X_(X), Y_(Y) {} struct Record; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool cell_unpack(Ref cell_ref, Record& data) const; bool pack(vm::CellBuilder& cb, const Record& data) const; @@ -776,7 +781,7 @@ struct HashmapAugNode final : TLB_Complex { }; struct Record_ahmn_fork; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record_ahmn_leaf& data) const; bool unpack_ahmn_leaf(vm::CellSlice& cs, Ref& extra, Ref& value) const; bool cell_unpack(Ref cell_ref, Record_ahmn_leaf& data) const; @@ -825,7 +830,7 @@ struct HashmapAugE final : TLB_Complex { }; struct Record_ahme_root; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record_ahme_empty& data) const; bool unpack_ahme_empty(vm::CellSlice& cs, Ref& extra) const; bool cell_unpack(Ref cell_ref, Record_ahme_empty& data) const; @@ -873,7 +878,7 @@ struct VarHashmap final : TLB_Complex { VarHashmap(int m, const TLB& X) : m_(m), X_(X) {} struct Record; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool cell_unpack(Ref cell_ref, Record& data) const; bool pack(vm::CellBuilder& cb, const Record& data) const; @@ -919,7 +924,7 @@ struct VarHashmapNode final : TLB_Complex { struct Record_vhmn_fork; struct Record_vhmn_cont; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record_vhmn_leaf& data) const; bool unpack_vhmn_leaf(vm::CellSlice& cs, Ref& value) const; bool cell_unpack(Ref cell_ref, Record_vhmn_leaf& data) const; @@ -987,7 +992,7 @@ struct VarHashmapE final : TLB_Complex { Record_vhme_root(Ref _root) : n(-1), root(std::move(_root)) {} }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record_vhme_empty& data) const; bool unpack_vhme_empty(vm::CellSlice& cs) const; bool cell_unpack(Ref cell_ref, Record_vhme_empty& data) const; @@ -1026,7 +1031,7 @@ struct PfxHashmap final : TLB_Complex { PfxHashmap(int m, const TLB& X) : m_(m), X_(X) {} struct Record; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool cell_unpack(Ref cell_ref, Record& data) const; bool pack(vm::CellBuilder& cb, const Record& data) const; @@ -1070,7 +1075,7 @@ struct PfxHashmapNode final : TLB_Complex { }; struct Record_phmn_fork; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record_phmn_leaf& data) const; bool unpack_phmn_leaf(vm::CellSlice& cs, Ref& value) const; bool cell_unpack(Ref cell_ref, Record_phmn_leaf& data) const; @@ -1127,7 +1132,7 @@ struct PfxHashmapE final : TLB_Complex { Record_phme_root(Ref _root) : n(-1), root(std::move(_root)) {} }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record_phme_empty& data) const; bool unpack_phme_empty(vm::CellSlice& cs) const; bool cell_unpack(Ref cell_ref, Record_phme_empty& data) const; @@ -1172,7 +1177,7 @@ struct MsgAddressExt final : TLB_Complex { Record_addr_extern(int _len, Ref _external_address) : len(_len), external_address(std::move(_external_address)) {} }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record_addr_none& data) const; bool unpack_addr_none(vm::CellSlice& cs) const; bool cell_unpack(Ref cell_ref, Record_addr_none& data) const; @@ -1216,7 +1221,7 @@ struct Anycast final : TLB_Complex { Record(int _depth, Ref _rewrite_pfx) : depth(_depth), rewrite_pfx(std::move(_rewrite_pfx)) {} }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_anycast_info(vm::CellSlice& cs, int& depth, Ref& rewrite_pfx) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -1248,7 +1253,7 @@ struct MsgAddressInt final : TLB_Complex { struct Record_addr_std; struct Record_addr_var; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record_addr_std& data) const; bool unpack_addr_std(vm::CellSlice& cs, Ref& anycast, int& workchain_id, td::BitArray<256>& address) const; bool cell_unpack(Ref cell_ref, Record_addr_std& data) const; @@ -1312,7 +1317,7 @@ struct MsgAddress final : TLB_Complex { Record_cons2(Ref _x) : x(std::move(_x)) {} }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record_cons1& data) const; bool unpack_cons1(vm::CellSlice& cs, Ref& x) const; bool cell_unpack(Ref cell_ref, Record_cons1& data) const; @@ -1352,7 +1357,7 @@ struct VarUInteger final : TLB_Complex { VarUInteger(int m) : m_(m) {} struct Record; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_var_uint(vm::CellSlice& cs, int& n, int& len, RefInt256& value) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -1391,7 +1396,7 @@ struct VarInteger final : TLB_Complex { VarInteger(int m) : m_(m) {} struct Record; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_var_int(vm::CellSlice& cs, int& n, int& len, RefInt256& value) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -1433,7 +1438,7 @@ struct Grams final : TLB_Complex { Record(Ref _amount) : amount(std::move(_amount)) {} }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_nanograms(vm::CellSlice& cs, Ref& amount) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -1468,7 +1473,7 @@ struct ExtraCurrencyCollection final : TLB_Complex { Record(Ref _dict) : dict(std::move(_dict)) {} }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_extra_currencies(vm::CellSlice& cs, Ref& dict) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -1504,7 +1509,7 @@ struct CurrencyCollection final : TLB_Complex { Record(Ref _grams, Ref _other) : grams(std::move(_grams)), other(std::move(_other)) {} }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_currencies(vm::CellSlice& cs, Ref& grams, Ref& other) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -1537,7 +1542,7 @@ struct CommonMsgInfo final : TLB_Complex { struct Record_ext_in_msg_info; struct Record_ext_out_msg_info; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record_int_msg_info& data) const; bool cell_unpack(Ref cell_ref, Record_int_msg_info& data) const; bool pack(vm::CellBuilder& cb, const Record_int_msg_info& data) const; @@ -1612,7 +1617,7 @@ struct CommonMsgInfoRelaxed final : TLB_Complex { struct Record_int_msg_info; struct Record_ext_out_msg_info; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record_int_msg_info& data) const; bool cell_unpack(Ref cell_ref, Record_int_msg_info& data) const; bool pack(vm::CellBuilder& cb, const Record_int_msg_info& data) const; @@ -1679,7 +1684,7 @@ struct TickTock final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return cs.advance(2); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override { + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override { return cs.advance(2); } bool unpack(vm::CellSlice& cs, Record& data) const; @@ -1711,7 +1716,7 @@ struct StateInit final : TLB_Complex { static constexpr int cons_len_exact = 0; struct Record; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool cell_unpack(Ref cell_ref, Record& data) const; bool pack(vm::CellBuilder& cb, const Record& data) const; @@ -1759,7 +1764,7 @@ struct SimpleLib final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return cs.advance_ext(0x10001); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_simple_lib(vm::CellSlice& cs, bool& public1, Ref& root) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -1791,7 +1796,7 @@ struct Message final : TLB_Complex { Message(const TLB& X) : X_(X) {} struct Record; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_message(vm::CellSlice& cs, Ref& info, Ref& init, Ref& body) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -1830,7 +1835,7 @@ struct MessageRelaxed final : TLB_Complex { MessageRelaxed(const TLB& X) : X_(X) {} struct Record; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_message(vm::CellSlice& cs, Ref& info, Ref& init, Ref& body) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -1887,7 +1892,7 @@ struct IntermediateAddress final : TLB_Complex { Record_interm_addr_ext(int _workchain_id, unsigned long long _addr_pfx) : workchain_id(_workchain_id), addr_pfx(_addr_pfx) {} }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record_interm_addr_regular& data) const; bool unpack_interm_addr_regular(vm::CellSlice& cs, int& use_dest_bits) const; bool cell_unpack(Ref cell_ref, Record_interm_addr_regular& data) const; @@ -1934,7 +1939,7 @@ struct MsgEnvelope final : TLB_Complex { static constexpr unsigned char cons_tag[1] = { 4 }; struct Record; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool cell_unpack(Ref cell_ref, Record& data) const; bool pack(vm::CellBuilder& cb, const Record& data) const; @@ -1983,7 +1988,7 @@ struct InMsg final : TLB_Complex { struct Record_msg_discard_fin; struct Record_msg_discard_tr; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record_msg_import_ext& data) const; bool unpack_msg_import_ext(vm::CellSlice& cs, Ref& msg, Ref& transaction) const; bool cell_unpack(Ref cell_ref, Record_msg_import_ext& data) const; @@ -2115,7 +2120,7 @@ struct ImportFees final : TLB_Complex { Record(Ref _fees_collected, Ref _value_imported) : fees_collected(std::move(_fees_collected)), value_imported(std::move(_value_imported)) {} }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_import_fees(vm::CellSlice& cs, Ref& fees_collected, Ref& value_imported) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -2150,7 +2155,7 @@ struct InMsgDescr final : TLB_Complex { Record(Ref _x) : x(std::move(_x)) {} }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_cons1(vm::CellSlice& cs, Ref& x) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -2223,7 +2228,7 @@ struct OutMsg final : TLB_Complex { Record_msg_export_deq_imm(Ref _out_msg, Ref _reimport) : out_msg(std::move(_out_msg)), reimport(std::move(_reimport)) {} }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record_msg_export_ext& data) const; bool unpack_msg_export_ext(vm::CellSlice& cs, Ref& msg, Ref& transaction) const; bool cell_unpack(Ref cell_ref, Record_msg_export_ext& data) const; @@ -2321,7 +2326,7 @@ struct EnqueuedMsg final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return cs.advance_ext(0x10040); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_cons1(vm::CellSlice& cs, unsigned long long& enqueued_lt, Ref& out_msg) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -2356,7 +2361,7 @@ struct OutMsgDescr final : TLB_Complex { Record(Ref _x) : x(std::move(_x)) {} }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_cons1(vm::CellSlice& cs, Ref& x) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -2391,7 +2396,7 @@ struct OutMsgQueue final : TLB_Complex { Record(Ref _x) : x(std::move(_x)) {} }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_cons1(vm::CellSlice& cs, Ref& x) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -2432,7 +2437,7 @@ struct ProcessedUpto final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return cs.advance(320); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override { + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override { return cs.advance(320); } bool unpack(vm::CellSlice& cs, Record& data) const; @@ -2469,7 +2474,7 @@ struct ProcessedInfo final : TLB_Complex { Record(Ref _x) : x(std::move(_x)) {} }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_cons1(vm::CellSlice& cs, Ref& x) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -2509,7 +2514,7 @@ struct IhrPendingSince final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return cs.advance(64); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override { + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override { return cs.advance(64); } bool unpack(vm::CellSlice& cs, Record& data) const; @@ -2546,7 +2551,7 @@ struct IhrPendingInfo final : TLB_Complex { Record(Ref _x) : x(std::move(_x)) {} }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_cons1(vm::CellSlice& cs, Ref& x) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -2576,7 +2581,7 @@ struct OutMsgQueueInfo final : TLB_Complex { static constexpr int cons_len_exact = 0; struct Record; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_cons1(vm::CellSlice& cs, Ref& out_queue, Ref& proc_info, Ref& ihr_pending) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -2615,7 +2620,7 @@ struct StorageUsed final : TLB_Complex { static constexpr int cons_len_exact = 0; struct Record; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_storage_used(vm::CellSlice& cs, Ref& cells, Ref& bits, Ref& public_cells) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -2660,7 +2665,7 @@ struct StorageUsedShort final : TLB_Complex { Record(Ref _cells, Ref _bits) : cells(std::move(_cells)), bits(std::move(_bits)) {} }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_storage_used_short(vm::CellSlice& cs, Ref& cells, Ref& bits) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -2690,7 +2695,7 @@ struct StorageInfo final : TLB_Complex { static constexpr int cons_len_exact = 0; struct Record; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_storage_info(vm::CellSlice& cs, Ref& used, unsigned& last_paid, Ref& due_payment) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -2732,7 +2737,7 @@ struct Account final : TLB_Complex { }; struct Record_account; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record_account_none& data) const; bool unpack_account_none(vm::CellSlice& cs) const; bool cell_unpack(Ref cell_ref, Record_account_none& data) const; @@ -2779,7 +2784,7 @@ struct AccountStorage final : TLB_Complex { static constexpr int cons_len_exact = 0; struct Record; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_account_storage(vm::CellSlice& cs, unsigned long long& last_trans_lt, Ref& balance, Ref& state) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -2833,7 +2838,7 @@ struct AccountState final : TLB_Complex { Record_account_frozen(const td::BitArray<256>& _state_hash) : state_hash(_state_hash) {} }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record_account_uninit& data) const; bool unpack_account_uninit(vm::CellSlice& cs) const; bool cell_unpack(Ref cell_ref, Record_account_uninit& data) const; @@ -2895,7 +2900,7 @@ struct AccountStatus final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return cs.advance(2); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override { + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override { return cs.advance(2); } bool fetch_enum_to(vm::CellSlice& cs, char& value) const; @@ -2958,7 +2963,7 @@ struct ShardAccount final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return cs.advance_ext(0x10140); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_account_descr(vm::CellSlice& cs, Ref& account, td::BitArray<256>& last_trans_hash, unsigned long long& last_trans_lt) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -3003,7 +3008,7 @@ struct DepthBalanceInfo final : TLB_Complex { Record(int _split_depth, Ref _balance) : split_depth(_split_depth), balance(std::move(_balance)) {} }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_depth_balance(vm::CellSlice& cs, int& split_depth, Ref& balance) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -3038,7 +3043,7 @@ struct ShardAccounts final : TLB_Complex { Record(Ref _x) : x(std::move(_x)) {} }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_cons1(vm::CellSlice& cs, Ref& x) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -3074,7 +3079,7 @@ struct Transaction_aux final : TLB_Complex { Record(Ref _in_msg, Ref _out_msgs) : in_msg(std::move(_in_msg)), out_msgs(std::move(_out_msgs)) {} }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_cons1(vm::CellSlice& cs, Ref& in_msg, Ref& out_msgs) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -3105,7 +3110,7 @@ struct Transaction final : TLB_Complex { static constexpr unsigned char cons_tag[1] = { 7 }; struct Record; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool cell_unpack(Ref cell_ref, Record& data) const; bool pack(vm::CellBuilder& cb, const Record& data) const; @@ -3160,7 +3165,7 @@ struct MERKLE_UPDATE final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return cs.advance_ext(0x20208); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool cell_unpack(Ref cell_ref, Record& data) const; bool pack(vm::CellBuilder& cb, const Record& data) const; @@ -3208,7 +3213,7 @@ struct HASH_UPDATE final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return cs.advance(520); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_update_hashes(vm::CellSlice& cs, td::BitArray<256>& old_hash, td::BitArray<256>& new_hash) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -3237,7 +3242,7 @@ struct AccountBlock final : TLB_Complex { static constexpr unsigned char cons_tag[1] = { 5 }; struct Record; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_acc_trans(vm::CellSlice& cs, td::BitArray<256>& account_addr, Ref& transactions, Ref& state_update) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -3281,7 +3286,7 @@ struct ShardAccountBlocks final : TLB_Complex { Record(Ref _x) : x(std::move(_x)) {} }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_cons1(vm::CellSlice& cs, Ref& x) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -3311,7 +3316,7 @@ struct TrStoragePhase final : TLB_Complex { static constexpr int cons_len_exact = 0; struct Record; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_tr_phase_storage(vm::CellSlice& cs, Ref& storage_fees_collected, Ref& storage_fees_due, char& status_change) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -3359,7 +3364,7 @@ struct AccStatusChange final : TLB_Complex { typedef AccStatusChange type_class; }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool fetch_enum_to(vm::CellSlice& cs, char& value) const; bool store_enum_from(vm::CellBuilder& cb, int value) const; bool unpack(vm::CellSlice& cs, Record_acst_unchanged& data) const; @@ -3413,7 +3418,7 @@ struct TrCreditPhase final : TLB_Complex { Record(Ref _due_fees_collected, Ref _credit) : due_fees_collected(std::move(_due_fees_collected)), credit(std::move(_credit)) {} }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_tr_phase_credit(vm::CellSlice& cs, Ref& due_fees_collected, Ref& credit) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -3443,7 +3448,7 @@ struct TrComputePhase_aux final : TLB_Complex { static constexpr int cons_len_exact = 0; struct Record; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool cell_unpack(Ref cell_ref, Record& data) const; bool pack(vm::CellBuilder& cb, const Record& data) const; @@ -3490,7 +3495,7 @@ struct TrComputePhase final : TLB_Complex { }; struct Record_tr_phase_compute_vm; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record_tr_phase_compute_skipped& data) const; bool unpack_tr_phase_compute_skipped(vm::CellSlice& cs, char& reason) const; bool cell_unpack(Ref cell_ref, Record_tr_phase_compute_skipped& data) const; @@ -3548,7 +3553,7 @@ struct ComputeSkipReason final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return cs.advance(2); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool fetch_enum_to(vm::CellSlice& cs, char& value) const; bool store_enum_from(vm::CellBuilder& cb, int value) const; bool unpack(vm::CellSlice& cs, Record_cskip_no_state& data) const; @@ -3596,7 +3601,7 @@ struct TrActionPhase final : TLB_Complex { static constexpr int cons_len_exact = 0; struct Record; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool cell_unpack(Ref cell_ref, Record& data) const; bool pack(vm::CellBuilder& cb, const Record& data) const; @@ -3653,7 +3658,7 @@ struct TrBouncePhase final : TLB_Complex { }; struct Record_tr_phase_bounce_ok; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record_tr_phase_bounce_negfunds& data) const; bool unpack_tr_phase_bounce_negfunds(vm::CellSlice& cs) const; bool cell_unpack(Ref cell_ref, Record_tr_phase_bounce_negfunds& data) const; @@ -3713,7 +3718,7 @@ struct SplitMergeInfo final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return cs.advance(524); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override { + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override { return cs.advance(524); } bool unpack(vm::CellSlice& cs, Record& data) const; @@ -3763,7 +3768,7 @@ struct TransactionDescr final : TLB_Complex { struct Record_trans_merge_prepare; struct Record_trans_merge_install; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record_trans_ord& data) const; bool cell_unpack(Ref cell_ref, Record_trans_ord& data) const; bool pack(vm::CellBuilder& cb, const Record_trans_ord& data) const; @@ -3896,7 +3901,7 @@ struct SmartContractInfo final : TLB_Complex { static constexpr unsigned cons_tag[1] = { 0x76ef1ea }; struct Record; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool cell_unpack(Ref cell_ref, Record& data) const; bool pack(vm::CellBuilder& cb, const Record& data) const; @@ -3941,7 +3946,7 @@ struct OutList final : TLB_Complex { }; struct Record_out_list; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record_out_list_empty& data) const; bool unpack_out_list_empty(vm::CellSlice& cs) const; bool cell_unpack(Ref cell_ref, Record_out_list_empty& data) const; @@ -3975,14 +3980,63 @@ struct OutList::Record_out_list { Record_out_list(Ref _prev, Ref _action) : n(-1), prev(std::move(_prev)), action(std::move(_action)) {} }; +// +// headers for type `LibRef` +// + +struct LibRef final : TLB_Complex { + enum { libref_hash, libref_ref }; + static constexpr int cons_len_exact = 1; + struct Record_libref_hash { + typedef LibRef type_class; + td::BitArray<256> lib_hash; // lib_hash : bits256 + Record_libref_hash() = default; + Record_libref_hash(const td::BitArray<256>& _lib_hash) : lib_hash(_lib_hash) {} + }; + struct Record_libref_ref { + typedef LibRef type_class; + Ref library; // library : ^Cell + Record_libref_ref() = default; + Record_libref_ref(Ref _library) : library(std::move(_library)) {} + }; + bool skip(vm::CellSlice& cs) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; + bool unpack(vm::CellSlice& cs, Record_libref_hash& data) const; + bool unpack_libref_hash(vm::CellSlice& cs, td::BitArray<256>& lib_hash) const; + bool cell_unpack(Ref cell_ref, Record_libref_hash& data) const; + bool cell_unpack_libref_hash(Ref cell_ref, td::BitArray<256>& lib_hash) const; + bool pack(vm::CellBuilder& cb, const Record_libref_hash& data) const; + bool pack_libref_hash(vm::CellBuilder& cb, td::BitArray<256> lib_hash) const; + bool cell_pack(Ref& cell_ref, const Record_libref_hash& data) const; + bool cell_pack_libref_hash(Ref& cell_ref, td::BitArray<256> lib_hash) const; + bool unpack(vm::CellSlice& cs, Record_libref_ref& data) const; + bool unpack_libref_ref(vm::CellSlice& cs, Ref& library) const; + bool cell_unpack(Ref cell_ref, Record_libref_ref& data) const; + bool cell_unpack_libref_ref(Ref cell_ref, Ref& library) const; + bool pack(vm::CellBuilder& cb, const Record_libref_ref& data) const; + bool pack_libref_ref(vm::CellBuilder& cb, Ref library) const; + bool cell_pack(Ref& cell_ref, const Record_libref_ref& data) const; + bool cell_pack_libref_ref(Ref& cell_ref, Ref library) const; + bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override; + std::ostream& print_type(std::ostream& os) const override { + return os << "LibRef"; + } + int check_tag(const vm::CellSlice& cs) const override; + int get_tag(const vm::CellSlice& cs) const override { + return (int)cs.prefetch_ulong(1); + } +}; + +extern const LibRef t_LibRef; + // // headers for type `OutAction` // struct OutAction final : TLB_Complex { - enum { action_send_msg, action_reserve_currency, action_set_code }; + enum { action_send_msg, action_change_library, action_reserve_currency, action_set_code }; static constexpr int cons_len_exact = 32; - static constexpr unsigned cons_tag[3] = { 0xec3c86d, 0x36e6b809, 0xad4de08eU }; + static constexpr unsigned cons_tag[4] = { 0xec3c86d, 0x26fa1dd4, 0x36e6b809, 0xad4de08eU }; struct Record_action_send_msg { typedef OutAction type_class; int mode; // mode : ## 8 @@ -4003,8 +4057,15 @@ struct OutAction final : TLB_Complex { Record_action_reserve_currency() = default; Record_action_reserve_currency(int _mode, Ref _currency) : mode(_mode), currency(std::move(_currency)) {} }; + struct Record_action_change_library { + typedef OutAction type_class; + int mode; // mode : ## 7 + Ref libref; // libref : LibRef + Record_action_change_library() = default; + Record_action_change_library(int _mode, Ref _libref) : mode(_mode), libref(std::move(_libref)) {} + }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record_action_send_msg& data) const; bool unpack_action_send_msg(vm::CellSlice& cs, int& mode, Ref& out_msg) const; bool cell_unpack(Ref cell_ref, Record_action_send_msg& data) const; @@ -4029,13 +4090,21 @@ struct OutAction final : TLB_Complex { bool pack_action_reserve_currency(vm::CellBuilder& cb, int mode, Ref currency) const; bool cell_pack(Ref& cell_ref, const Record_action_reserve_currency& data) const; bool cell_pack_action_reserve_currency(Ref& cell_ref, int mode, Ref currency) const; + bool unpack(vm::CellSlice& cs, Record_action_change_library& data) const; + bool unpack_action_change_library(vm::CellSlice& cs, int& mode, Ref& libref) const; + bool cell_unpack(Ref cell_ref, Record_action_change_library& data) const; + bool cell_unpack_action_change_library(Ref cell_ref, int& mode, Ref& libref) const; + bool pack(vm::CellBuilder& cb, const Record_action_change_library& data) const; + bool pack_action_change_library(vm::CellBuilder& cb, int mode, Ref libref) const; + bool cell_pack(Ref& cell_ref, const Record_action_change_library& data) const; + bool cell_pack_action_change_library(Ref& cell_ref, int mode, Ref libref) const; bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override; std::ostream& print_type(std::ostream& os) const override { return os << "OutAction"; } int check_tag(const vm::CellSlice& cs) const override; int get_tag(const vm::CellSlice& cs) const override { - return cs.bselect(3, 0x23); + return cs.bselect(4, 0x40d); } }; @@ -4056,7 +4125,7 @@ struct OutListNode final : TLB_Complex { Record(Ref _prev, Ref _action) : prev(std::move(_prev)), action(std::move(_action)) {} }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_out_list_node(vm::CellSlice& cs, Ref& prev, Ref& action) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -4091,7 +4160,7 @@ struct ShardIdent final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return cs.advance(104); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_shard_ident(vm::CellSlice& cs, int& shard_pfx_bits, int& workchain_id, unsigned long long& shard_prefix) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -4135,7 +4204,7 @@ struct ExtBlkRef final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return cs.advance(608); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override { + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override { return cs.advance(608); } bool unpack(vm::CellSlice& cs, Record& data) const; @@ -4178,7 +4247,7 @@ struct BlockIdExt final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return cs.advance(648); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool cell_unpack(Ref cell_ref, Record& data) const; bool pack(vm::CellBuilder& cb, const Record& data) const; @@ -4224,7 +4293,7 @@ struct BlkMasterInfo final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return cs.advance(608); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override { + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override { return cs.advance(608); } bool unpack(vm::CellSlice& cs, Record& data) const; @@ -4256,7 +4325,7 @@ struct ShardStateUnsplit_aux final : TLB_Complex { static constexpr int cons_len_exact = 0; struct Record; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool cell_unpack(Ref cell_ref, Record& data) const; bool pack(vm::CellBuilder& cb, const Record& data) const; @@ -4295,7 +4364,7 @@ struct ShardStateUnsplit final : TLB_Complex { static constexpr unsigned cons_tag[1] = { 0x9023afe2U }; struct Record; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool cell_unpack(Ref cell_ref, Record& data) const; bool pack(vm::CellBuilder& cb, const Record& data) const; @@ -4352,7 +4421,7 @@ struct ShardState final : TLB_Complex { Record_split_state(Ref _left, Ref _right) : left(std::move(_left)), right(std::move(_right)) {} }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record_cons1& data) const; bool unpack_cons1(vm::CellSlice& cs, Ref& x) const; bool cell_unpack(Ref cell_ref, Record_cons1& data) const; @@ -4396,7 +4465,7 @@ struct LibDescr final : TLB_Complex { Record(Ref _lib, Ref _publishers) : lib(std::move(_lib)), publishers(std::move(_publishers)) {} }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_shared_lib_descr(vm::CellSlice& cs, Ref& lib, Ref& publishers) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -4427,7 +4496,7 @@ struct BlockInfo final : TLB_Complex { static constexpr unsigned cons_tag[1] = { 0x9bc7a987U }; struct Record; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool cell_unpack(Ref cell_ref, Record& data) const; bool pack(vm::CellBuilder& cb, const Record& data) const; @@ -4496,7 +4565,7 @@ struct BlkPrevInfo final : TLB_Complex { Record_prev_blks_info(Ref _prev1, Ref _prev2) : prev1(std::move(_prev1)), prev2(std::move(_prev2)) {} }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record_prev_blk_info& data) const; bool unpack_prev_blk_info(vm::CellSlice& cs, Ref& prev) const; bool cell_unpack(Ref cell_ref, Record_prev_blk_info& data) const; @@ -4536,7 +4605,7 @@ struct Block final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return cs.advance_ext(0x40040); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool cell_unpack(Ref cell_ref, Record& data) const; bool pack(vm::CellBuilder& cb, const Record& data) const; @@ -4574,7 +4643,7 @@ struct BlockExtra final : TLB_Complex { static constexpr unsigned cons_tag[1] = { 0x4a33f6fd }; struct Record; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool cell_unpack(Ref cell_ref, Record& data) const; bool pack(vm::CellBuilder& cb, const Record& data) const; @@ -4612,7 +4681,7 @@ struct ValueFlow_aux final : TLB_Complex { static constexpr int cons_len_exact = 0; struct Record; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool cell_unpack(Ref cell_ref, Record& data) const; bool pack(vm::CellBuilder& cb, const Record& data) const; @@ -4648,7 +4717,7 @@ struct ValueFlow_aux1 final : TLB_Complex { static constexpr int cons_len_exact = 0; struct Record; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool cell_unpack(Ref cell_ref, Record& data) const; bool pack(vm::CellBuilder& cb, const Record& data) const; @@ -4685,7 +4754,7 @@ struct ValueFlow final : TLB_Complex { static constexpr unsigned cons_tag[1] = { 0xb8e48dfbU }; struct Record; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool cell_unpack(Ref cell_ref, Record& data) const; bool pack(vm::CellBuilder& cb, const Record& data) const; @@ -4734,7 +4803,7 @@ struct BinTree final : TLB_Complex { Record_bt_fork(Ref _left, Ref _right) : left(std::move(_left)), right(std::move(_right)) {} }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record_bt_leaf& data) const; bool unpack_bt_leaf(vm::CellSlice& cs, Ref& leaf) const; bool cell_unpack(Ref cell_ref, Record_bt_leaf& data) const; @@ -4787,7 +4856,7 @@ struct FutureSplitMerge final : TLB_Complex { Record_fsm_merge(unsigned _merge_utime, unsigned _interval) : merge_utime(_merge_utime), interval(_interval) {} }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record_fsm_none& data) const; bool unpack_fsm_none(vm::CellSlice& cs) const; bool cell_unpack(Ref cell_ref, Record_fsm_none& data) const; @@ -4834,7 +4903,7 @@ struct ShardDescr final : TLB_Complex { static constexpr unsigned char cons_tag[1] = { 11 }; struct Record; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool cell_unpack(Ref cell_ref, Record& data) const; bool pack(vm::CellBuilder& cb, const Record& data) const; @@ -4890,7 +4959,7 @@ struct ShardHashes final : TLB_Complex { Record(Ref _x) : x(std::move(_x)) {} }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_cons1(vm::CellSlice& cs, Ref& x) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -4929,7 +4998,7 @@ struct BinTreeAug final : TLB_Complex { }; struct Record_bta_fork; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record_bta_leaf& data) const; bool unpack_bta_leaf(vm::CellSlice& cs, Ref& extra, Ref& leaf) const; bool cell_unpack(Ref cell_ref, Record_bta_leaf& data) const; @@ -4980,7 +5049,7 @@ struct ShardFeeCreated final : TLB_Complex { Record(Ref _fees, Ref _create) : fees(std::move(_fees)), create(std::move(_create)) {} }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_cons1(vm::CellSlice& cs, Ref& fees, Ref& create) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -5015,7 +5084,7 @@ struct ShardFees final : TLB_Complex { Record(Ref _x) : x(std::move(_x)) {} }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_cons1(vm::CellSlice& cs, Ref& x) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -5056,7 +5125,7 @@ struct ConfigParams final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return cs.advance_ext(0x10100); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_cons1(vm::CellSlice& cs, td::BitArray<256>& config_addr, Ref& config) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -5091,7 +5160,7 @@ struct ValidatorInfo final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return cs.advance(65); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override { + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override { return cs.advance(65); } bool unpack(vm::CellSlice& cs, Record& data) const; @@ -5143,7 +5212,7 @@ struct ValidatorBaseInfo final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return cs.advance(64); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override { + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override { return cs.advance(64); } bool unpack(vm::CellSlice& cs, Record& data) const; @@ -5186,7 +5255,7 @@ struct KeyMaxLt final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return cs.advance(65); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override { + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override { return cs.advance(65); } bool unpack(vm::CellSlice& cs, Record& data) const; @@ -5229,7 +5298,7 @@ struct KeyExtBlkRef final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return cs.advance(609); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override { + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override { return cs.advance(609); } bool unpack(vm::CellSlice& cs, Record& data) const; @@ -5266,7 +5335,7 @@ struct OldMcBlocksInfo final : TLB_Complex { Record(Ref _x) : x(std::move(_x)) {} }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_cons1(vm::CellSlice& cs, Ref& x) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -5301,7 +5370,7 @@ struct Counters final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return cs.advance(224); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override { + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override { return cs.advance(224); } bool unpack(vm::CellSlice& cs, Record& data) const; @@ -5351,7 +5420,7 @@ struct CreatorStats final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return cs.advance(452); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_creator_info(vm::CellSlice& cs, Ref& mc_blocks, Ref& shard_blocks) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -5377,32 +5446,46 @@ extern const CreatorStats t_CreatorStats; // struct BlockCreateStats final : TLB_Complex { - enum { block_create_stats }; + enum { block_create_stats, block_create_stats_ext }; static constexpr int cons_len_exact = 8; - static constexpr unsigned char cons_tag[1] = { 23 }; - struct Record { + static constexpr unsigned char cons_tag[2] = { 23, 0x34 }; + struct Record_block_create_stats { typedef BlockCreateStats type_class; Ref counters; // counters : HashmapE 256 CreatorStats - Record() = default; - Record(Ref _counters) : counters(std::move(_counters)) {} + Record_block_create_stats() = default; + Record_block_create_stats(Ref _counters) : counters(std::move(_counters)) {} + }; + struct Record_block_create_stats_ext { + typedef BlockCreateStats type_class; + Ref counters; // counters : HashmapAugE 256 CreatorStats uint32 + Record_block_create_stats_ext() = default; + Record_block_create_stats_ext(Ref _counters) : counters(std::move(_counters)) {} }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; - bool unpack(vm::CellSlice& cs, Record& data) const; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; + bool unpack(vm::CellSlice& cs, Record_block_create_stats& data) const; bool unpack_block_create_stats(vm::CellSlice& cs, Ref& counters) const; - bool cell_unpack(Ref cell_ref, Record& data) const; + bool cell_unpack(Ref cell_ref, Record_block_create_stats& data) const; bool cell_unpack_block_create_stats(Ref cell_ref, Ref& counters) const; - bool pack(vm::CellBuilder& cb, const Record& data) const; + bool pack(vm::CellBuilder& cb, const Record_block_create_stats& data) const; bool pack_block_create_stats(vm::CellBuilder& cb, Ref counters) const; - bool cell_pack(Ref& cell_ref, const Record& data) const; + bool cell_pack(Ref& cell_ref, const Record_block_create_stats& data) const; bool cell_pack_block_create_stats(Ref& cell_ref, Ref counters) const; + bool unpack(vm::CellSlice& cs, Record_block_create_stats_ext& data) const; + bool unpack_block_create_stats_ext(vm::CellSlice& cs, Ref& counters) const; + bool cell_unpack(Ref cell_ref, Record_block_create_stats_ext& data) const; + bool cell_unpack_block_create_stats_ext(Ref cell_ref, Ref& counters) const; + bool pack(vm::CellBuilder& cb, const Record_block_create_stats_ext& data) const; + bool pack_block_create_stats_ext(vm::CellBuilder& cb, Ref counters) const; + bool cell_pack(Ref& cell_ref, const Record_block_create_stats_ext& data) const; + bool cell_pack_block_create_stats_ext(Ref& cell_ref, Ref counters) const; bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override; std::ostream& print_type(std::ostream& os) const override { return os << "BlockCreateStats"; } int check_tag(const vm::CellSlice& cs) const override; int get_tag(const vm::CellSlice& cs) const override { - return 0; + return cs.bselect(3, 3); } }; @@ -5417,7 +5500,7 @@ struct McStateExtra_aux final : TLB_Complex { static constexpr int cons_len_exact = 0; struct Record; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool cell_unpack(Ref cell_ref, Record& data) const; bool pack(vm::CellBuilder& cb, const Record& data) const; @@ -5456,7 +5539,7 @@ struct McStateExtra final : TLB_Complex { static constexpr unsigned short cons_tag[1] = { 0xcc26 }; struct Record; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool cell_unpack(Ref cell_ref, Record& data) const; bool pack(vm::CellBuilder& cb, const Record& data) const; @@ -5503,7 +5586,7 @@ struct SigPubKey final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return cs.advance(288); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_ed25519_pubkey(vm::CellSlice& cs, td::BitArray<256>& pubkey) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -5545,7 +5628,7 @@ struct CryptoSignatureSimple final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return cs.advance(516); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_ed25519_signature(vm::CellSlice& cs, td::BitArray<256>& R, td::BitArray<256>& s) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -5581,7 +5664,7 @@ struct CryptoSignaturePair final : TLB_Complex { Record(const td::BitArray<256>& _node_id_short, Ref _sign) : node_id_short(_node_id_short), sign(std::move(_sign)) {} }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_sig_pair(vm::CellSlice& cs, td::BitArray<256>& node_id_short, Ref& sign) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -5617,7 +5700,7 @@ struct Certificate final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return cs.advance(356); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_certificate(vm::CellSlice& cs, Ref& temp_key, unsigned& valid_since, unsigned& valid_until) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -5667,7 +5750,7 @@ struct CertificateEnv final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return cs.advance(384); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_certificate_env(vm::CellSlice& cs, Ref& certificate) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -5703,7 +5786,7 @@ struct SignedCertificate final : TLB_Complex { Record(Ref _certificate, Ref _certificate_signature) : certificate(std::move(_certificate)), certificate_signature(std::move(_certificate_signature)) {} }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_signed_certificate(vm::CellSlice& cs, Ref& certificate, Ref& certificate_signature) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -5746,7 +5829,7 @@ struct CryptoSignature final : TLB_Complex { Record_chained_signature(Ref _signed_cert, Ref _temp_key_signature) : signed_cert(std::move(_signed_cert)), temp_key_signature(std::move(_temp_key_signature)) {} }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record_cons1& data) const; bool unpack_cons1(vm::CellSlice& cs, Ref& x) const; bool cell_unpack(Ref cell_ref, Record_cons1& data) const; @@ -5784,7 +5867,7 @@ struct McBlockExtra_aux final : TLB_Complex { static constexpr int cons_len_exact = 0; struct Record; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_cons1(vm::CellSlice& cs, Ref& prev_blk_signatures, Ref& recover_create_msg, Ref& mint_msg) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -5824,7 +5907,7 @@ struct McBlockExtra final : TLB_Complex { static constexpr unsigned short cons_tag[1] = { 0xcca5 }; struct Record; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool cell_unpack(Ref cell_ref, Record& data) const; bool pack(vm::CellBuilder& cb, const Record& data) const; @@ -5869,7 +5952,7 @@ struct ValidatorDescr final : TLB_Complex { }; struct Record_validator_addr; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record_validator& data) const; bool unpack_validator(vm::CellSlice& cs, Ref& public_key, unsigned long long& weight) const; bool cell_unpack(Ref cell_ref, Record_validator& data) const; @@ -5918,7 +6001,7 @@ struct ValidatorSet final : TLB_Complex { struct Record_validators; struct Record_validators_ext; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record_validators& data) const; bool cell_unpack(Ref cell_ref, Record_validators& data) const; bool pack(vm::CellBuilder& cb, const Record_validators& data) const; @@ -5981,7 +6064,7 @@ struct GlobalVersion final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return cs.advance(104); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_capabilities(vm::CellSlice& cs, unsigned& version, unsigned long long& capabilities) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -6020,7 +6103,7 @@ struct WorkchainFormat final : TLB_Complex { }; struct Record_wfmt_ext; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record_wfmt_basic& data) const; bool unpack_wfmt_basic(vm::CellSlice& cs, int& vm_version, unsigned long long& vm_mode) const; bool cell_unpack(Ref cell_ref, Record_wfmt_basic& data) const; @@ -6063,7 +6146,7 @@ struct WorkchainDescr final : TLB_Complex { static constexpr unsigned char cons_tag[1] = { 0xa6 }; struct Record; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool cell_unpack(Ref cell_ref, Record& data) const; bool pack(vm::CellBuilder& cb, const Record& data) const; @@ -6114,7 +6197,7 @@ struct BlockCreateFees final : TLB_Complex { Record(Ref _masterchain_block_fee, Ref _basechain_block_fee) : masterchain_block_fee(std::move(_masterchain_block_fee)), basechain_block_fee(std::move(_basechain_block_fee)) {} }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_block_grams_created(vm::CellSlice& cs, Ref& masterchain_block_fee, Ref& basechain_block_fee) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -6150,7 +6233,7 @@ struct StoragePrices final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return cs.advance(296); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool cell_unpack(Ref cell_ref, Record& data) const; bool pack(vm::CellBuilder& cb, const Record& data) const; @@ -6190,7 +6273,7 @@ struct GasLimitsPrices final : TLB_Complex { struct Record_gas_prices_ext; struct Record_gas_flat_pfx; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record_gas_prices& data) const; bool cell_unpack(Ref cell_ref, Record_gas_prices& data) const; bool pack(vm::CellBuilder& cb, const Record_gas_prices& data) const; @@ -6266,7 +6349,7 @@ struct ParamLimits final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return cs.advance(104); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_param_limits(vm::CellSlice& cs, int& underload, int& soft_limit, int& hard_limit) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -6311,7 +6394,7 @@ struct BlockLimits final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return cs.advance(320); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_block_limits(vm::CellSlice& cs, Ref& bytes, Ref& gas, Ref& lt_delta) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -6356,7 +6439,7 @@ struct MsgForwardPrices final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return cs.advance(264); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool cell_unpack(Ref cell_ref, Record& data) const; bool pack(vm::CellBuilder& cb, const Record& data) const; @@ -6400,7 +6483,7 @@ struct CatchainConfig final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return cs.advance(136); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool cell_unpack(Ref cell_ref, Record& data) const; bool pack(vm::CellBuilder& cb, const Record& data) const; @@ -6442,7 +6525,7 @@ struct ConsensusConfig final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return cs.advance(264); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool cell_unpack(Ref cell_ref, Record& data) const; bool pack(vm::CellBuilder& cb, const Record& data) const; @@ -6488,7 +6571,7 @@ struct ValidatorTempKey final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return cs.advance(612); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool cell_unpack(Ref cell_ref, Record& data) const; bool pack(vm::CellBuilder& cb, const Record& data) const; @@ -6531,7 +6614,7 @@ struct ValidatorSignedTempKey final : TLB_Complex { Record(Ref _key, Ref _signature) : key(std::move(_key)), signature(std::move(_signature)) {} }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_signed_temp_key(vm::CellSlice& cs, Ref& key, Ref& signature) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -6734,7 +6817,7 @@ struct ConfigParam final : TLB_Complex { Record_cons39(Ref _x) : x(std::move(_x)) {} }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record_cons0& data) const; bool unpack_cons0(vm::CellSlice& cs, td::BitArray<256>& config_addr) const; bool cell_unpack(Ref cell_ref, Record_cons0& data) const; @@ -7021,7 +7104,7 @@ struct BlockSignaturesPure final : TLB_Complex { static constexpr int cons_len_exact = 0; struct Record; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_block_signatures_pure(vm::CellSlice& cs, unsigned& sig_count, unsigned long long& sig_weight, Ref& signatures) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -7067,7 +7150,7 @@ struct BlockSignatures final : TLB_Complex { Record(Ref _validator_info, Ref _pure_signatures) : validator_info(std::move(_validator_info)), pure_signatures(std::move(_pure_signatures)) {} }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_block_signatures(vm::CellSlice& cs, Ref& validator_info, Ref& pure_signatures) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -7098,7 +7181,7 @@ struct BlockProof final : TLB_Complex { static constexpr unsigned char cons_tag[1] = { 0xc3 }; struct Record; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_block_proof(vm::CellSlice& cs, Ref& proof_for, Ref& root, Ref& signatures) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -7142,7 +7225,7 @@ struct ProofChain final : TLB_Complex { }; struct Record_chain_link; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record_chain_empty& data) const; bool unpack_chain_empty(vm::CellSlice& cs) const; bool cell_unpack(Ref cell_ref, Record_chain_empty& data) const; @@ -7186,7 +7269,7 @@ struct TopBlockDescr final : TLB_Complex { static constexpr unsigned char cons_tag[1] = { 0xd5 }; struct Record; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool cell_unpack(Ref cell_ref, Record& data) const; bool pack(vm::CellBuilder& cb, const Record& data) const; @@ -7228,7 +7311,7 @@ struct TopBlockDescrSet final : TLB_Complex { Record(Ref _collection) : collection(std::move(_collection)) {} }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, Record& data) const; bool unpack_top_block_descr_set(vm::CellSlice& cs, Ref& collection) const; bool cell_unpack(Ref cell_ref, Record& data) const; @@ -7249,6 +7332,1194 @@ struct TopBlockDescrSet final : TLB_Complex { extern const TopBlockDescrSet t_TopBlockDescrSet; +// +// headers for type `VmCellSlice` +// + +struct VmCellSlice final : TLB_Complex { + enum { cons1 }; + static constexpr int cons_len_exact = 0; + struct Record; + int get_size(const vm::CellSlice& cs) const override { + return 0x1001a; + } + bool skip(vm::CellSlice& cs) const override { + return cs.advance_ext(0x1001a); + } + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; + bool unpack(vm::CellSlice& cs, Record& data) const; + bool cell_unpack(Ref cell_ref, Record& data) const; + bool pack(vm::CellBuilder& cb, const Record& data) const; + bool cell_pack(Ref& cell_ref, const Record& data) const; + bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override; + std::ostream& print_type(std::ostream& os) const override { + return os << "VmCellSlice"; + } + int check_tag(const vm::CellSlice& cs) const override; + int get_tag(const vm::CellSlice& cs) const override { + return 0; + } +}; + +struct VmCellSlice::Record { + typedef VmCellSlice type_class; + Ref cell; // cell : ^Cell + int st_bits; // st_bits : ## 10 + int end_bits; // end_bits : ## 10 + int st_ref; // st_ref : #<= 4 + int end_ref; // end_ref : #<= 4 + Record() = default; + Record(Ref _cell, int _st_bits, int _end_bits, int _st_ref, int _end_ref) : cell(std::move(_cell)), st_bits(_st_bits), end_bits(_end_bits), st_ref(_st_ref), end_ref(_end_ref) {} +}; + +extern const VmCellSlice t_VmCellSlice; + +// +// headers for type `VmTupleRef` +// + +struct VmTupleRef final : TLB_Complex { + enum { vm_tupref_nil, vm_tupref_single, vm_tupref_any }; + static constexpr int cons_len_exact = 0; + int m_; + VmTupleRef(int m) : m_(m) {} + struct Record_vm_tupref_nil { + typedef VmTupleRef type_class; + }; + struct Record_vm_tupref_single { + typedef VmTupleRef type_class; + Ref entry; // entry : ^VmStackValue + Record_vm_tupref_single() = default; + Record_vm_tupref_single(Ref _entry) : entry(std::move(_entry)) {} + }; + struct Record_vm_tupref_any { + typedef VmTupleRef type_class; + int n; // n : # + Ref ref; // ref : ^(VmTuple (n + 2)) + Record_vm_tupref_any() = default; + Record_vm_tupref_any(Ref _ref) : n(-1), ref(std::move(_ref)) {} + }; + bool skip(vm::CellSlice& cs) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; + bool unpack(vm::CellSlice& cs, Record_vm_tupref_nil& data) const; + bool unpack_vm_tupref_nil(vm::CellSlice& cs) const; + bool cell_unpack(Ref cell_ref, Record_vm_tupref_nil& data) const; + bool cell_unpack_vm_tupref_nil(Ref cell_ref) const; + bool pack(vm::CellBuilder& cb, const Record_vm_tupref_nil& data) const; + bool pack_vm_tupref_nil(vm::CellBuilder& cb) const; + bool cell_pack(Ref& cell_ref, const Record_vm_tupref_nil& data) const; + bool cell_pack_vm_tupref_nil(Ref& cell_ref) const; + bool unpack(vm::CellSlice& cs, Record_vm_tupref_single& data) const; + bool unpack_vm_tupref_single(vm::CellSlice& cs, Ref& entry) const; + bool cell_unpack(Ref cell_ref, Record_vm_tupref_single& data) const; + bool cell_unpack_vm_tupref_single(Ref cell_ref, Ref& entry) const; + bool pack(vm::CellBuilder& cb, const Record_vm_tupref_single& data) const; + bool pack_vm_tupref_single(vm::CellBuilder& cb, Ref entry) const; + bool cell_pack(Ref& cell_ref, const Record_vm_tupref_single& data) const; + bool cell_pack_vm_tupref_single(Ref& cell_ref, Ref entry) const; + bool unpack(vm::CellSlice& cs, Record_vm_tupref_any& data) const; + bool unpack_vm_tupref_any(vm::CellSlice& cs, int& n, Ref& ref) const; + bool cell_unpack(Ref cell_ref, Record_vm_tupref_any& data) const; + bool cell_unpack_vm_tupref_any(Ref cell_ref, int& n, Ref& ref) const; + bool pack(vm::CellBuilder& cb, const Record_vm_tupref_any& data) const; + bool pack_vm_tupref_any(vm::CellBuilder& cb, Ref ref) const; + bool cell_pack(Ref& cell_ref, const Record_vm_tupref_any& data) const; + bool cell_pack_vm_tupref_any(Ref& cell_ref, Ref ref) const; + bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override; + std::ostream& print_type(std::ostream& os) const override { + return os << "(VmTupleRef " << m_ << ")"; + } + int check_tag(const vm::CellSlice& cs) const override; + int get_tag(const vm::CellSlice& cs) const override; +}; + +// +// headers for type `VmTuple` +// + +struct VmTuple final : TLB_Complex { + enum { vm_tuple_nil, vm_tuple_tcons }; + static constexpr int cons_len_exact = 0; + int m_; + VmTuple(int m) : m_(m) {} + struct Record_vm_tuple_nil { + typedef VmTuple type_class; + }; + struct Record_vm_tuple_tcons; + bool skip(vm::CellSlice& cs) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; + bool unpack(vm::CellSlice& cs, Record_vm_tuple_nil& data) const; + bool unpack_vm_tuple_nil(vm::CellSlice& cs) const; + bool cell_unpack(Ref cell_ref, Record_vm_tuple_nil& data) const; + bool cell_unpack_vm_tuple_nil(Ref cell_ref) const; + bool pack(vm::CellBuilder& cb, const Record_vm_tuple_nil& data) const; + bool pack_vm_tuple_nil(vm::CellBuilder& cb) const; + bool cell_pack(Ref& cell_ref, const Record_vm_tuple_nil& data) const; + bool cell_pack_vm_tuple_nil(Ref& cell_ref) const; + bool unpack(vm::CellSlice& cs, Record_vm_tuple_tcons& data) const; + bool unpack_vm_tuple_tcons(vm::CellSlice& cs, int& n, Ref& head, Ref& tail) const; + bool cell_unpack(Ref cell_ref, Record_vm_tuple_tcons& data) const; + bool cell_unpack_vm_tuple_tcons(Ref cell_ref, int& n, Ref& head, Ref& tail) const; + bool pack(vm::CellBuilder& cb, const Record_vm_tuple_tcons& data) const; + bool pack_vm_tuple_tcons(vm::CellBuilder& cb, Ref head, Ref tail) const; + bool cell_pack(Ref& cell_ref, const Record_vm_tuple_tcons& data) const; + bool cell_pack_vm_tuple_tcons(Ref& cell_ref, Ref head, Ref tail) const; + bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override; + std::ostream& print_type(std::ostream& os) const override { + return os << "(VmTuple " << m_ << ")"; + } + int check_tag(const vm::CellSlice& cs) const override; + int get_tag(const vm::CellSlice& cs) const override; +}; + +struct VmTuple::Record_vm_tuple_tcons { + typedef VmTuple type_class; + int n; // n : # + Ref head; // head : VmTupleRef n + Ref tail; // tail : ^VmStackValue + Record_vm_tuple_tcons() = default; + Record_vm_tuple_tcons(Ref _head, Ref _tail) : n(-1), head(std::move(_head)), tail(std::move(_tail)) {} +}; + +// +// headers for type `VmStackValue` +// + +struct VmStackValue final : TLB_Complex { + enum { vm_stk_null, vm_stk_tinyint, vm_stk_int, vm_stk_nan, vm_stk_cell, vm_stk_slice, vm_stk_builder, vm_stk_cont, vm_stk_tuple }; + static constexpr char cons_len[9] = { 8, 8, 15, 16, 8, 8, 8, 8, 8 }; + static constexpr unsigned short cons_tag[9] = { 0, 1, 0x100, 0x2ff, 3, 4, 5, 6, 7 }; + struct Record_vm_stk_null { + typedef VmStackValue type_class; + }; + struct Record_vm_stk_tinyint { + typedef VmStackValue type_class; + long long value; // value : int64 + Record_vm_stk_tinyint() = default; + Record_vm_stk_tinyint(long long _value) : value(_value) {} + }; + struct Record_vm_stk_int { + typedef VmStackValue type_class; + RefInt256 value; // value : int257 + Record_vm_stk_int() = default; + Record_vm_stk_int(RefInt256 _value) : value(std::move(_value)) {} + }; + struct Record_vm_stk_nan { + typedef VmStackValue type_class; + }; + struct Record_vm_stk_cell { + typedef VmStackValue type_class; + Ref cell; // cell : ^Cell + Record_vm_stk_cell() = default; + Record_vm_stk_cell(Ref _cell) : cell(std::move(_cell)) {} + }; + struct Record_vm_stk_slice { + typedef VmStackValue type_class; + Ref x; // VmCellSlice + Record_vm_stk_slice() = default; + Record_vm_stk_slice(Ref _x) : x(std::move(_x)) {} + }; + struct Record_vm_stk_builder { + typedef VmStackValue type_class; + Ref cell; // cell : ^Cell + Record_vm_stk_builder() = default; + Record_vm_stk_builder(Ref _cell) : cell(std::move(_cell)) {} + }; + struct Record_vm_stk_cont { + typedef VmStackValue type_class; + Ref cont; // cont : VmCont + Record_vm_stk_cont() = default; + Record_vm_stk_cont(Ref _cont) : cont(std::move(_cont)) {} + }; + struct Record_vm_stk_tuple { + typedef VmStackValue type_class; + int len; // len : ## 16 + Ref data; // data : VmTuple len + Record_vm_stk_tuple() = default; + Record_vm_stk_tuple(int _len, Ref _data) : len(_len), data(std::move(_data)) {} + }; + bool skip(vm::CellSlice& cs) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; + bool unpack(vm::CellSlice& cs, Record_vm_stk_null& data) const; + bool unpack_vm_stk_null(vm::CellSlice& cs) const; + bool cell_unpack(Ref cell_ref, Record_vm_stk_null& data) const; + bool cell_unpack_vm_stk_null(Ref cell_ref) const; + bool pack(vm::CellBuilder& cb, const Record_vm_stk_null& data) const; + bool pack_vm_stk_null(vm::CellBuilder& cb) const; + bool cell_pack(Ref& cell_ref, const Record_vm_stk_null& data) const; + bool cell_pack_vm_stk_null(Ref& cell_ref) const; + bool unpack(vm::CellSlice& cs, Record_vm_stk_tinyint& data) const; + bool unpack_vm_stk_tinyint(vm::CellSlice& cs, long long& value) const; + bool cell_unpack(Ref cell_ref, Record_vm_stk_tinyint& data) const; + bool cell_unpack_vm_stk_tinyint(Ref cell_ref, long long& value) const; + bool pack(vm::CellBuilder& cb, const Record_vm_stk_tinyint& data) const; + bool pack_vm_stk_tinyint(vm::CellBuilder& cb, long long value) const; + bool cell_pack(Ref& cell_ref, const Record_vm_stk_tinyint& data) const; + bool cell_pack_vm_stk_tinyint(Ref& cell_ref, long long value) const; + bool unpack(vm::CellSlice& cs, Record_vm_stk_int& data) const; + bool unpack_vm_stk_int(vm::CellSlice& cs, RefInt256& value) const; + bool cell_unpack(Ref cell_ref, Record_vm_stk_int& data) const; + bool cell_unpack_vm_stk_int(Ref cell_ref, RefInt256& value) const; + bool pack(vm::CellBuilder& cb, const Record_vm_stk_int& data) const; + bool pack_vm_stk_int(vm::CellBuilder& cb, RefInt256 value) const; + bool cell_pack(Ref& cell_ref, const Record_vm_stk_int& data) const; + bool cell_pack_vm_stk_int(Ref& cell_ref, RefInt256 value) const; + bool unpack(vm::CellSlice& cs, Record_vm_stk_nan& data) const; + bool unpack_vm_stk_nan(vm::CellSlice& cs) const; + bool cell_unpack(Ref cell_ref, Record_vm_stk_nan& data) const; + bool cell_unpack_vm_stk_nan(Ref cell_ref) const; + bool pack(vm::CellBuilder& cb, const Record_vm_stk_nan& data) const; + bool pack_vm_stk_nan(vm::CellBuilder& cb) const; + bool cell_pack(Ref& cell_ref, const Record_vm_stk_nan& data) const; + bool cell_pack_vm_stk_nan(Ref& cell_ref) const; + bool unpack(vm::CellSlice& cs, Record_vm_stk_cell& data) const; + bool unpack_vm_stk_cell(vm::CellSlice& cs, Ref& cell) const; + bool cell_unpack(Ref cell_ref, Record_vm_stk_cell& data) const; + bool cell_unpack_vm_stk_cell(Ref cell_ref, Ref& cell) const; + bool pack(vm::CellBuilder& cb, const Record_vm_stk_cell& data) const; + bool pack_vm_stk_cell(vm::CellBuilder& cb, Ref cell) const; + bool cell_pack(Ref& cell_ref, const Record_vm_stk_cell& data) const; + bool cell_pack_vm_stk_cell(Ref& cell_ref, Ref cell) const; + bool unpack(vm::CellSlice& cs, Record_vm_stk_slice& data) const; + bool unpack_vm_stk_slice(vm::CellSlice& cs, Ref& x) const; + bool cell_unpack(Ref cell_ref, Record_vm_stk_slice& data) const; + bool cell_unpack_vm_stk_slice(Ref cell_ref, Ref& x) const; + bool pack(vm::CellBuilder& cb, const Record_vm_stk_slice& data) const; + bool pack_vm_stk_slice(vm::CellBuilder& cb, Ref x) const; + bool cell_pack(Ref& cell_ref, const Record_vm_stk_slice& data) const; + bool cell_pack_vm_stk_slice(Ref& cell_ref, Ref x) const; + bool unpack(vm::CellSlice& cs, Record_vm_stk_builder& data) const; + bool unpack_vm_stk_builder(vm::CellSlice& cs, Ref& cell) const; + bool cell_unpack(Ref cell_ref, Record_vm_stk_builder& data) const; + bool cell_unpack_vm_stk_builder(Ref cell_ref, Ref& cell) const; + bool pack(vm::CellBuilder& cb, const Record_vm_stk_builder& data) const; + bool pack_vm_stk_builder(vm::CellBuilder& cb, Ref cell) const; + bool cell_pack(Ref& cell_ref, const Record_vm_stk_builder& data) const; + bool cell_pack_vm_stk_builder(Ref& cell_ref, Ref cell) const; + bool unpack(vm::CellSlice& cs, Record_vm_stk_cont& data) const; + bool unpack_vm_stk_cont(vm::CellSlice& cs, Ref& cont) const; + bool cell_unpack(Ref cell_ref, Record_vm_stk_cont& data) const; + bool cell_unpack_vm_stk_cont(Ref cell_ref, Ref& cont) const; + bool pack(vm::CellBuilder& cb, const Record_vm_stk_cont& data) const; + bool pack_vm_stk_cont(vm::CellBuilder& cb, Ref cont) const; + bool cell_pack(Ref& cell_ref, const Record_vm_stk_cont& data) const; + bool cell_pack_vm_stk_cont(Ref& cell_ref, Ref cont) const; + bool unpack(vm::CellSlice& cs, Record_vm_stk_tuple& data) const; + bool unpack_vm_stk_tuple(vm::CellSlice& cs, int& len, Ref& data) const; + bool cell_unpack(Ref cell_ref, Record_vm_stk_tuple& data) const; + bool cell_unpack_vm_stk_tuple(Ref cell_ref, int& len, Ref& data) const; + bool pack(vm::CellBuilder& cb, const Record_vm_stk_tuple& data) const; + bool pack_vm_stk_tuple(vm::CellBuilder& cb, int len, Ref data) const; + bool cell_pack(Ref& cell_ref, const Record_vm_stk_tuple& data) const; + bool cell_pack_vm_stk_tuple(Ref& cell_ref, int len, Ref data) const; + bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override; + std::ostream& print_type(std::ostream& os) const override { + return os << "VmStackValue"; + } + int check_tag(const vm::CellSlice& cs) const override; + int get_tag(const vm::CellSlice& cs) const override; +}; + +extern const VmStackValue t_VmStackValue; + +// +// headers for type `VmStack` +// + +struct VmStack final : TLB_Complex { + enum { vm_stack }; + static constexpr int cons_len_exact = 0; + struct Record { + typedef VmStack type_class; + int depth; // depth : ## 24 + Ref stack; // stack : VmStackList depth + Record() = default; + Record(int _depth, Ref _stack) : depth(_depth), stack(std::move(_stack)) {} + }; + bool skip(vm::CellSlice& cs) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; + bool unpack(vm::CellSlice& cs, Record& data) const; + bool unpack_vm_stack(vm::CellSlice& cs, int& depth, Ref& stack) const; + bool cell_unpack(Ref cell_ref, Record& data) const; + bool cell_unpack_vm_stack(Ref cell_ref, int& depth, Ref& stack) const; + bool pack(vm::CellBuilder& cb, const Record& data) const; + bool pack_vm_stack(vm::CellBuilder& cb, int depth, Ref stack) const; + bool cell_pack(Ref& cell_ref, const Record& data) const; + bool cell_pack_vm_stack(Ref& cell_ref, int depth, Ref stack) const; + bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override; + std::ostream& print_type(std::ostream& os) const override { + return os << "VmStack"; + } + int check_tag(const vm::CellSlice& cs) const override; + int get_tag(const vm::CellSlice& cs) const override { + return 0; + } +}; + +extern const VmStack t_VmStack; + +// +// headers for type `VmStackList` +// + +struct VmStackList final : TLB_Complex { + enum { vm_stk_cons, vm_stk_nil }; + static constexpr int cons_len_exact = 0; + int m_; + VmStackList(int m) : m_(m) {} + struct Record_vm_stk_cons; + struct Record_vm_stk_nil { + typedef VmStackList type_class; + }; + bool skip(vm::CellSlice& cs) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; + bool unpack(vm::CellSlice& cs, Record_vm_stk_cons& data) const; + bool unpack_vm_stk_cons(vm::CellSlice& cs, int& n, Ref& rest, Ref& tos) const; + bool cell_unpack(Ref cell_ref, Record_vm_stk_cons& data) const; + bool cell_unpack_vm_stk_cons(Ref cell_ref, int& n, Ref& rest, Ref& tos) const; + bool pack(vm::CellBuilder& cb, const Record_vm_stk_cons& data) const; + bool pack_vm_stk_cons(vm::CellBuilder& cb, Ref rest, Ref tos) const; + bool cell_pack(Ref& cell_ref, const Record_vm_stk_cons& data) const; + bool cell_pack_vm_stk_cons(Ref& cell_ref, Ref rest, Ref tos) const; + bool unpack(vm::CellSlice& cs, Record_vm_stk_nil& data) const; + bool unpack_vm_stk_nil(vm::CellSlice& cs) const; + bool cell_unpack(Ref cell_ref, Record_vm_stk_nil& data) const; + bool cell_unpack_vm_stk_nil(Ref cell_ref) const; + bool pack(vm::CellBuilder& cb, const Record_vm_stk_nil& data) const; + bool pack_vm_stk_nil(vm::CellBuilder& cb) const; + bool cell_pack(Ref& cell_ref, const Record_vm_stk_nil& data) const; + bool cell_pack_vm_stk_nil(Ref& cell_ref) const; + bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override; + std::ostream& print_type(std::ostream& os) const override { + return os << "(VmStackList " << m_ << ")"; + } + int check_tag(const vm::CellSlice& cs) const override; + int get_tag(const vm::CellSlice& cs) const override; +}; + +struct VmStackList::Record_vm_stk_cons { + typedef VmStackList type_class; + int n; // n : # + Ref rest; // rest : ^(VmStackList n) + Ref tos; // tos : VmStackValue + Record_vm_stk_cons() = default; + Record_vm_stk_cons(Ref _rest, Ref _tos) : n(-1), rest(std::move(_rest)), tos(std::move(_tos)) {} +}; + +// +// headers for type `VmSaveList` +// + +struct VmSaveList final : TLB_Complex { + enum { cons1 }; + static constexpr int cons_len_exact = 0; + struct Record { + typedef VmSaveList type_class; + Ref cregs; // cregs : HashmapE 4 VmStackValue + Record() = default; + Record(Ref _cregs) : cregs(std::move(_cregs)) {} + }; + bool skip(vm::CellSlice& cs) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; + bool unpack(vm::CellSlice& cs, Record& data) const; + bool unpack_cons1(vm::CellSlice& cs, Ref& cregs) const; + bool cell_unpack(Ref cell_ref, Record& data) const; + bool cell_unpack_cons1(Ref cell_ref, Ref& cregs) const; + bool pack(vm::CellBuilder& cb, const Record& data) const; + bool pack_cons1(vm::CellBuilder& cb, Ref cregs) const; + bool cell_pack(Ref& cell_ref, const Record& data) const; + bool cell_pack_cons1(Ref& cell_ref, Ref cregs) const; + bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override; + std::ostream& print_type(std::ostream& os) const override { + return os << "VmSaveList"; + } + int check_tag(const vm::CellSlice& cs) const override; + int get_tag(const vm::CellSlice& cs) const override { + return 0; + } +}; + +extern const VmSaveList t_VmSaveList; + +// +// headers for auxiliary type `VmGasLimits_aux` +// + +struct VmGasLimits_aux final : TLB_Complex { + enum { cons1 }; + static constexpr int cons_len_exact = 0; + struct Record; + int get_size(const vm::CellSlice& cs) const override { + return 192; + } + bool skip(vm::CellSlice& cs) const override { + return cs.advance(192); + } + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override { + return cs.advance(192); + } + bool unpack(vm::CellSlice& cs, Record& data) const; + bool unpack_cons1(vm::CellSlice& cs, long long& max_limit, long long& cur_limit, long long& credit) const; + bool cell_unpack(Ref cell_ref, Record& data) const; + bool cell_unpack_cons1(Ref cell_ref, long long& max_limit, long long& cur_limit, long long& credit) const; + bool pack(vm::CellBuilder& cb, const Record& data) const; + bool pack_cons1(vm::CellBuilder& cb, long long max_limit, long long cur_limit, long long credit) const; + bool cell_pack(Ref& cell_ref, const Record& data) const; + bool cell_pack_cons1(Ref& cell_ref, long long max_limit, long long cur_limit, long long credit) const; + bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override; + std::ostream& print_type(std::ostream& os) const override { + return os << "VmGasLimits_aux"; + } + int check_tag(const vm::CellSlice& cs) const override; + int get_tag(const vm::CellSlice& cs) const override { + return 0; + } +}; + +struct VmGasLimits_aux::Record { + typedef VmGasLimits_aux type_class; + long long max_limit; // max_limit : int64 + long long cur_limit; // cur_limit : int64 + long long credit; // credit : int64 + Record() = default; + Record(long long _max_limit, long long _cur_limit, long long _credit) : max_limit(_max_limit), cur_limit(_cur_limit), credit(_credit) {} +}; + +extern const VmGasLimits_aux t_VmGasLimits_aux; + +// +// headers for type `VmGasLimits` +// + +struct VmGasLimits final : TLB_Complex { + enum { gas_limits }; + static constexpr int cons_len_exact = 0; + struct Record { + typedef VmGasLimits type_class; + long long remaining; // remaining : int64 + VmGasLimits_aux::Record r1; // ^[$_ max_limit:int64 cur_limit:int64 credit:int64 ] + Record() = default; + Record(long long _remaining, const VmGasLimits_aux::Record& _r1) : remaining(_remaining), r1(_r1) {} + }; + int get_size(const vm::CellSlice& cs) const override { + return 0x10040; + } + bool skip(vm::CellSlice& cs) const override { + return cs.advance_ext(0x10040); + } + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; + bool unpack(vm::CellSlice& cs, Record& data) const; + bool cell_unpack(Ref cell_ref, Record& data) const; + bool pack(vm::CellBuilder& cb, const Record& data) const; + bool cell_pack(Ref& cell_ref, const Record& data) const; + bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override; + std::ostream& print_type(std::ostream& os) const override { + return os << "VmGasLimits"; + } + int check_tag(const vm::CellSlice& cs) const override; + int get_tag(const vm::CellSlice& cs) const override { + return 0; + } +}; + +extern const VmGasLimits t_VmGasLimits; + +// +// headers for type `VmLibraries` +// + +struct VmLibraries final : TLB_Complex { + enum { cons1 }; + static constexpr int cons_len_exact = 0; + struct Record { + typedef VmLibraries type_class; + Ref libraries; // libraries : HashmapE 256 ^Cell + Record() = default; + Record(Ref _libraries) : libraries(std::move(_libraries)) {} + }; + bool skip(vm::CellSlice& cs) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; + bool unpack(vm::CellSlice& cs, Record& data) const; + bool unpack_cons1(vm::CellSlice& cs, Ref& libraries) const; + bool cell_unpack(Ref cell_ref, Record& data) const; + bool cell_unpack_cons1(Ref cell_ref, Ref& libraries) const; + bool pack(vm::CellBuilder& cb, const Record& data) const; + bool pack_cons1(vm::CellBuilder& cb, Ref libraries) const; + bool cell_pack(Ref& cell_ref, const Record& data) const; + bool cell_pack_cons1(Ref& cell_ref, Ref libraries) const; + bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override; + std::ostream& print_type(std::ostream& os) const override { + return os << "VmLibraries"; + } + int check_tag(const vm::CellSlice& cs) const override; + int get_tag(const vm::CellSlice& cs) const override { + return 0; + } +}; + +extern const VmLibraries t_VmLibraries; + +// +// headers for type `VmControlData` +// + +struct VmControlData final : TLB_Complex { + enum { vm_ctl_data }; + static constexpr int cons_len_exact = 0; + struct Record; + bool skip(vm::CellSlice& cs) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; + bool unpack(vm::CellSlice& cs, Record& data) const; + bool cell_unpack(Ref cell_ref, Record& data) const; + bool pack(vm::CellBuilder& cb, const Record& data) const; + bool cell_pack(Ref& cell_ref, const Record& data) const; + bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override; + std::ostream& print_type(std::ostream& os) const override { + return os << "VmControlData"; + } + int check_tag(const vm::CellSlice& cs) const override; + int get_tag(const vm::CellSlice& cs) const override { + return 0; + } +}; + +struct VmControlData::Record { + typedef VmControlData type_class; + Ref nargs; // nargs : Maybe uint13 + Ref stack; // stack : Maybe VmStack + Ref save; // save : VmSaveList + Ref cp; // cp : Maybe int16 + Record() = default; + Record(Ref _nargs, Ref _stack, Ref _save, Ref _cp) : nargs(std::move(_nargs)), stack(std::move(_stack)), save(std::move(_save)), cp(std::move(_cp)) {} +}; + +extern const VmControlData t_VmControlData; + +// +// headers for type `VmCont` +// + +struct VmCont final : TLB_Complex { + enum { vmc_std, vmc_envelope, vmc_quit, vmc_quit_exc, vmc_repeat, vmc_until, vmc_again, vmc_while_cond, vmc_while_body, vmc_pushint }; + static constexpr char cons_len[10] = { 2, 2, 4, 4, 5, 6, 6, 6, 6, 4 }; + static constexpr unsigned char cons_tag[10] = { 0, 1, 8, 9, 20, 0x30, 0x31, 0x32, 0x33, 15 }; + struct Record_vmc_std { + typedef VmCont type_class; + Ref cdata; // cdata : VmControlData + Ref code; // code : VmCellSlice + Record_vmc_std() = default; + Record_vmc_std(Ref _cdata, Ref _code) : cdata(std::move(_cdata)), code(std::move(_code)) {} + }; + struct Record_vmc_envelope { + typedef VmCont type_class; + Ref cdata; // cdata : VmControlData + Ref next; // next : ^VmCont + Record_vmc_envelope() = default; + Record_vmc_envelope(Ref _cdata, Ref _next) : cdata(std::move(_cdata)), next(std::move(_next)) {} + }; + struct Record_vmc_quit { + typedef VmCont type_class; + int exit_code; // exit_code : int32 + Record_vmc_quit() = default; + Record_vmc_quit(int _exit_code) : exit_code(_exit_code) {} + }; + struct Record_vmc_quit_exc { + typedef VmCont type_class; + }; + struct Record_vmc_repeat; + struct Record_vmc_until { + typedef VmCont type_class; + Ref body; // body : ^VmCont + Ref after; // after : ^VmCont + Record_vmc_until() = default; + Record_vmc_until(Ref _body, Ref _after) : body(std::move(_body)), after(std::move(_after)) {} + }; + struct Record_vmc_again { + typedef VmCont type_class; + Ref body; // body : ^VmCont + Record_vmc_again() = default; + Record_vmc_again(Ref _body) : body(std::move(_body)) {} + }; + struct Record_vmc_while_cond; + struct Record_vmc_while_body; + struct Record_vmc_pushint { + typedef VmCont type_class; + int value; // value : int32 + Ref next; // next : ^VmCont + Record_vmc_pushint() = default; + Record_vmc_pushint(int _value, Ref _next) : value(_value), next(std::move(_next)) {} + }; + bool skip(vm::CellSlice& cs) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; + bool unpack(vm::CellSlice& cs, Record_vmc_std& data) const; + bool unpack_vmc_std(vm::CellSlice& cs, Ref& cdata, Ref& code) const; + bool cell_unpack(Ref cell_ref, Record_vmc_std& data) const; + bool cell_unpack_vmc_std(Ref cell_ref, Ref& cdata, Ref& code) const; + bool pack(vm::CellBuilder& cb, const Record_vmc_std& data) const; + bool pack_vmc_std(vm::CellBuilder& cb, Ref cdata, Ref code) const; + bool cell_pack(Ref& cell_ref, const Record_vmc_std& data) const; + bool cell_pack_vmc_std(Ref& cell_ref, Ref cdata, Ref code) const; + bool unpack(vm::CellSlice& cs, Record_vmc_envelope& data) const; + bool unpack_vmc_envelope(vm::CellSlice& cs, Ref& cdata, Ref& next) const; + bool cell_unpack(Ref cell_ref, Record_vmc_envelope& data) const; + bool cell_unpack_vmc_envelope(Ref cell_ref, Ref& cdata, Ref& next) const; + bool pack(vm::CellBuilder& cb, const Record_vmc_envelope& data) const; + bool pack_vmc_envelope(vm::CellBuilder& cb, Ref cdata, Ref next) const; + bool cell_pack(Ref& cell_ref, const Record_vmc_envelope& data) const; + bool cell_pack_vmc_envelope(Ref& cell_ref, Ref cdata, Ref next) const; + bool unpack(vm::CellSlice& cs, Record_vmc_quit& data) const; + bool unpack_vmc_quit(vm::CellSlice& cs, int& exit_code) const; + bool cell_unpack(Ref cell_ref, Record_vmc_quit& data) const; + bool cell_unpack_vmc_quit(Ref cell_ref, int& exit_code) const; + bool pack(vm::CellBuilder& cb, const Record_vmc_quit& data) const; + bool pack_vmc_quit(vm::CellBuilder& cb, int exit_code) const; + bool cell_pack(Ref& cell_ref, const Record_vmc_quit& data) const; + bool cell_pack_vmc_quit(Ref& cell_ref, int exit_code) const; + bool unpack(vm::CellSlice& cs, Record_vmc_quit_exc& data) const; + bool unpack_vmc_quit_exc(vm::CellSlice& cs) const; + bool cell_unpack(Ref cell_ref, Record_vmc_quit_exc& data) const; + bool cell_unpack_vmc_quit_exc(Ref cell_ref) const; + bool pack(vm::CellBuilder& cb, const Record_vmc_quit_exc& data) const; + bool pack_vmc_quit_exc(vm::CellBuilder& cb) const; + bool cell_pack(Ref& cell_ref, const Record_vmc_quit_exc& data) const; + bool cell_pack_vmc_quit_exc(Ref& cell_ref) const; + bool unpack(vm::CellSlice& cs, Record_vmc_repeat& data) const; + bool unpack_vmc_repeat(vm::CellSlice& cs, long long& count, Ref& body, Ref& after) const; + bool cell_unpack(Ref cell_ref, Record_vmc_repeat& data) const; + bool cell_unpack_vmc_repeat(Ref cell_ref, long long& count, Ref& body, Ref& after) const; + bool pack(vm::CellBuilder& cb, const Record_vmc_repeat& data) const; + bool pack_vmc_repeat(vm::CellBuilder& cb, long long count, Ref body, Ref after) const; + bool cell_pack(Ref& cell_ref, const Record_vmc_repeat& data) const; + bool cell_pack_vmc_repeat(Ref& cell_ref, long long count, Ref body, Ref after) const; + bool unpack(vm::CellSlice& cs, Record_vmc_until& data) const; + bool unpack_vmc_until(vm::CellSlice& cs, Ref& body, Ref& after) const; + bool cell_unpack(Ref cell_ref, Record_vmc_until& data) const; + bool cell_unpack_vmc_until(Ref cell_ref, Ref& body, Ref& after) const; + bool pack(vm::CellBuilder& cb, const Record_vmc_until& data) const; + bool pack_vmc_until(vm::CellBuilder& cb, Ref body, Ref after) const; + bool cell_pack(Ref& cell_ref, const Record_vmc_until& data) const; + bool cell_pack_vmc_until(Ref& cell_ref, Ref body, Ref after) const; + bool unpack(vm::CellSlice& cs, Record_vmc_again& data) const; + bool unpack_vmc_again(vm::CellSlice& cs, Ref& body) const; + bool cell_unpack(Ref cell_ref, Record_vmc_again& data) const; + bool cell_unpack_vmc_again(Ref cell_ref, Ref& body) const; + bool pack(vm::CellBuilder& cb, const Record_vmc_again& data) const; + bool pack_vmc_again(vm::CellBuilder& cb, Ref body) const; + bool cell_pack(Ref& cell_ref, const Record_vmc_again& data) const; + bool cell_pack_vmc_again(Ref& cell_ref, Ref body) const; + bool unpack(vm::CellSlice& cs, Record_vmc_while_cond& data) const; + bool unpack_vmc_while_cond(vm::CellSlice& cs, Ref& cond, Ref& body, Ref& after) const; + bool cell_unpack(Ref cell_ref, Record_vmc_while_cond& data) const; + bool cell_unpack_vmc_while_cond(Ref cell_ref, Ref& cond, Ref& body, Ref& after) const; + bool pack(vm::CellBuilder& cb, const Record_vmc_while_cond& data) const; + bool pack_vmc_while_cond(vm::CellBuilder& cb, Ref cond, Ref body, Ref after) const; + bool cell_pack(Ref& cell_ref, const Record_vmc_while_cond& data) const; + bool cell_pack_vmc_while_cond(Ref& cell_ref, Ref cond, Ref body, Ref after) const; + bool unpack(vm::CellSlice& cs, Record_vmc_while_body& data) const; + bool unpack_vmc_while_body(vm::CellSlice& cs, Ref& cond, Ref& body, Ref& after) const; + bool cell_unpack(Ref cell_ref, Record_vmc_while_body& data) const; + bool cell_unpack_vmc_while_body(Ref cell_ref, Ref& cond, Ref& body, Ref& after) const; + bool pack(vm::CellBuilder& cb, const Record_vmc_while_body& data) const; + bool pack_vmc_while_body(vm::CellBuilder& cb, Ref cond, Ref body, Ref after) const; + bool cell_pack(Ref& cell_ref, const Record_vmc_while_body& data) const; + bool cell_pack_vmc_while_body(Ref& cell_ref, Ref cond, Ref body, Ref after) const; + bool unpack(vm::CellSlice& cs, Record_vmc_pushint& data) const; + bool unpack_vmc_pushint(vm::CellSlice& cs, int& value, Ref& next) const; + bool cell_unpack(Ref cell_ref, Record_vmc_pushint& data) const; + bool cell_unpack_vmc_pushint(Ref cell_ref, int& value, Ref& next) const; + bool pack(vm::CellBuilder& cb, const Record_vmc_pushint& data) const; + bool pack_vmc_pushint(vm::CellBuilder& cb, int value, Ref next) const; + bool cell_pack(Ref& cell_ref, const Record_vmc_pushint& data) const; + bool cell_pack_vmc_pushint(Ref& cell_ref, int value, Ref next) const; + bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override; + std::ostream& print_type(std::ostream& os) const override { + return os << "VmCont"; + } + int check_tag(const vm::CellSlice& cs) const override; + int get_tag(const vm::CellSlice& cs) const override { + return cs.bselect_ext(6, 0x100f011100010001ULL); + } +}; + +struct VmCont::Record_vmc_repeat { + typedef VmCont type_class; + long long count; // count : uint63 + Ref body; // body : ^VmCont + Ref after; // after : ^VmCont + Record_vmc_repeat() = default; + Record_vmc_repeat(long long _count, Ref _body, Ref _after) : count(_count), body(std::move(_body)), after(std::move(_after)) {} +}; + +struct VmCont::Record_vmc_while_cond { + typedef VmCont type_class; + Ref cond; // cond : ^VmCont + Ref body; // body : ^VmCont + Ref after; // after : ^VmCont + Record_vmc_while_cond() = default; + Record_vmc_while_cond(Ref _cond, Ref _body, Ref _after) : cond(std::move(_cond)), body(std::move(_body)), after(std::move(_after)) {} +}; + +struct VmCont::Record_vmc_while_body { + typedef VmCont type_class; + Ref cond; // cond : ^VmCont + Ref body; // body : ^VmCont + Ref after; // after : ^VmCont + Record_vmc_while_body() = default; + Record_vmc_while_body(Ref _cond, Ref _body, Ref _after) : cond(std::move(_cond)), body(std::move(_body)), after(std::move(_after)) {} +}; + +extern const VmCont t_VmCont; + +// +// headers for type `DNS_RecordSet` +// + +struct DNS_RecordSet final : TLB_Complex { + enum { cons1 }; + static constexpr int cons_len_exact = 0; + struct Record { + typedef DNS_RecordSet type_class; + Ref x; // HashmapE 16 ^DNSRecord + Record() = default; + Record(Ref _x) : x(std::move(_x)) {} + }; + bool skip(vm::CellSlice& cs) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; + bool unpack(vm::CellSlice& cs, Record& data) const; + bool unpack_cons1(vm::CellSlice& cs, Ref& x) const; + bool cell_unpack(Ref cell_ref, Record& data) const; + bool cell_unpack_cons1(Ref cell_ref, Ref& x) const; + bool pack(vm::CellBuilder& cb, const Record& data) const; + bool pack_cons1(vm::CellBuilder& cb, Ref x) const; + bool cell_pack(Ref& cell_ref, const Record& data) const; + bool cell_pack_cons1(Ref& cell_ref, Ref x) const; + bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override; + std::ostream& print_type(std::ostream& os) const override { + return os << "DNS_RecordSet"; + } + int check_tag(const vm::CellSlice& cs) const override; + int get_tag(const vm::CellSlice& cs) const override { + return 0; + } +}; + +extern const DNS_RecordSet t_DNS_RecordSet; + +// +// headers for type `TextChunkRef` +// + +struct TextChunkRef final : TLB_Complex { + enum { chunk_ref, chunk_ref_empty }; + static constexpr int cons_len_exact = 0; + int m_; + TextChunkRef(int m) : m_(m) {} + struct Record_chunk_ref { + typedef TextChunkRef type_class; + int n; // n : # + Ref ref; // ref : ^(TextChunks (n + 1)) + Record_chunk_ref() = default; + Record_chunk_ref(Ref _ref) : n(-1), ref(std::move(_ref)) {} + }; + struct Record_chunk_ref_empty { + typedef TextChunkRef type_class; + }; + bool skip(vm::CellSlice& cs) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; + bool unpack(vm::CellSlice& cs, Record_chunk_ref& data) const; + bool unpack_chunk_ref(vm::CellSlice& cs, int& n, Ref& ref) const; + bool cell_unpack(Ref cell_ref, Record_chunk_ref& data) const; + bool cell_unpack_chunk_ref(Ref cell_ref, int& n, Ref& ref) const; + bool pack(vm::CellBuilder& cb, const Record_chunk_ref& data) const; + bool pack_chunk_ref(vm::CellBuilder& cb, Ref ref) const; + bool cell_pack(Ref& cell_ref, const Record_chunk_ref& data) const; + bool cell_pack_chunk_ref(Ref& cell_ref, Ref ref) const; + bool unpack(vm::CellSlice& cs, Record_chunk_ref_empty& data) const; + bool unpack_chunk_ref_empty(vm::CellSlice& cs) const; + bool cell_unpack(Ref cell_ref, Record_chunk_ref_empty& data) const; + bool cell_unpack_chunk_ref_empty(Ref cell_ref) const; + bool pack(vm::CellBuilder& cb, const Record_chunk_ref_empty& data) const; + bool pack_chunk_ref_empty(vm::CellBuilder& cb) const; + bool cell_pack(Ref& cell_ref, const Record_chunk_ref_empty& data) const; + bool cell_pack_chunk_ref_empty(Ref& cell_ref) const; + bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override; + std::ostream& print_type(std::ostream& os) const override { + return os << "(TextChunkRef " << m_ << ")"; + } + int check_tag(const vm::CellSlice& cs) const override; + int get_tag(const vm::CellSlice& cs) const override; +}; + +// +// headers for type `TextChunks` +// + +struct TextChunks final : TLB_Complex { + enum { text_chunk, text_chunk_empty }; + static constexpr int cons_len_exact = 0; + int m_; + TextChunks(int m) : m_(m) {} + struct Record_text_chunk; + struct Record_text_chunk_empty { + typedef TextChunks type_class; + }; + bool skip(vm::CellSlice& cs) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; + bool unpack(vm::CellSlice& cs, Record_text_chunk& data) const; + bool cell_unpack(Ref cell_ref, Record_text_chunk& data) const; + bool pack(vm::CellBuilder& cb, const Record_text_chunk& data) const; + bool cell_pack(Ref& cell_ref, const Record_text_chunk& data) const; + bool unpack(vm::CellSlice& cs, Record_text_chunk_empty& data) const; + bool unpack_text_chunk_empty(vm::CellSlice& cs) const; + bool cell_unpack(Ref cell_ref, Record_text_chunk_empty& data) const; + bool cell_unpack_text_chunk_empty(Ref cell_ref) const; + bool pack(vm::CellBuilder& cb, const Record_text_chunk_empty& data) const; + bool pack_text_chunk_empty(vm::CellBuilder& cb) const; + bool cell_pack(Ref& cell_ref, const Record_text_chunk_empty& data) const; + bool cell_pack_text_chunk_empty(Ref& cell_ref) const; + bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override; + std::ostream& print_type(std::ostream& os) const override { + return os << "(TextChunks " << m_ << ")"; + } + int check_tag(const vm::CellSlice& cs) const override; + int get_tag(const vm::CellSlice& cs) const override; +}; + +struct TextChunks::Record_text_chunk { + typedef TextChunks type_class; + int n; // n : # + int len; // len : ## 8 + Ref data; // data : bits (8 * len) + Ref next; // next : TextChunkRef n + Record_text_chunk() = default; + Record_text_chunk(int _len, Ref _data, Ref _next) : n(-1), len(_len), data(std::move(_data)), next(std::move(_next)) {} +}; + +// +// headers for type `Text` +// + +struct Text final : TLB_Complex { + enum { text }; + static constexpr int cons_len_exact = 0; + struct Record { + typedef Text type_class; + int chunks; // chunks : ## 8 + Ref rest; // rest : TextChunks chunks + Record() = default; + Record(int _chunks, Ref _rest) : chunks(_chunks), rest(std::move(_rest)) {} + }; + bool skip(vm::CellSlice& cs) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; + bool unpack(vm::CellSlice& cs, Record& data) const; + bool unpack_text(vm::CellSlice& cs, int& chunks, Ref& rest) const; + bool cell_unpack(Ref cell_ref, Record& data) const; + bool cell_unpack_text(Ref cell_ref, int& chunks, Ref& rest) const; + bool pack(vm::CellBuilder& cb, const Record& data) const; + bool pack_text(vm::CellBuilder& cb, int chunks, Ref rest) const; + bool cell_pack(Ref& cell_ref, const Record& data) const; + bool cell_pack_text(Ref& cell_ref, int chunks, Ref rest) const; + bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override; + std::ostream& print_type(std::ostream& os) const override { + return os << "Text"; + } + int check_tag(const vm::CellSlice& cs) const override; + int get_tag(const vm::CellSlice& cs) const override { + return 0; + } +}; + +extern const Text t_Text; + +// +// headers for type `ProtoList` +// + +struct ProtoList final : TLB_Complex { + enum { proto_list_nil, proto_list_next }; + static constexpr int cons_len_exact = 1; + struct Record_proto_list_nil { + typedef ProtoList type_class; + }; + struct Record_proto_list_next { + typedef ProtoList type_class; + char head; // head : Protocol + Ref tail; // tail : ProtoList + Record_proto_list_next() = default; + Record_proto_list_next(char _head, Ref _tail) : head(_head), tail(std::move(_tail)) {} + }; + bool skip(vm::CellSlice& cs) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; + bool unpack(vm::CellSlice& cs, Record_proto_list_nil& data) const; + bool unpack_proto_list_nil(vm::CellSlice& cs) const; + bool cell_unpack(Ref cell_ref, Record_proto_list_nil& data) const; + bool cell_unpack_proto_list_nil(Ref cell_ref) const; + bool pack(vm::CellBuilder& cb, const Record_proto_list_nil& data) const; + bool pack_proto_list_nil(vm::CellBuilder& cb) const; + bool cell_pack(Ref& cell_ref, const Record_proto_list_nil& data) const; + bool cell_pack_proto_list_nil(Ref& cell_ref) const; + bool unpack(vm::CellSlice& cs, Record_proto_list_next& data) const; + bool unpack_proto_list_next(vm::CellSlice& cs, char& head, Ref& tail) const; + bool cell_unpack(Ref cell_ref, Record_proto_list_next& data) const; + bool cell_unpack_proto_list_next(Ref cell_ref, char& head, Ref& tail) const; + bool pack(vm::CellBuilder& cb, const Record_proto_list_next& data) const; + bool pack_proto_list_next(vm::CellBuilder& cb, char head, Ref tail) const; + bool cell_pack(Ref& cell_ref, const Record_proto_list_next& data) const; + bool cell_pack_proto_list_next(Ref& cell_ref, char head, Ref tail) const; + bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override; + std::ostream& print_type(std::ostream& os) const override { + return os << "ProtoList"; + } + int check_tag(const vm::CellSlice& cs) const override; + int get_tag(const vm::CellSlice& cs) const override { + return (int)cs.prefetch_ulong(1); + } +}; + +extern const ProtoList t_ProtoList; + +// +// headers for type `Protocol` +// + +struct Protocol final : TLB_Complex { + enum { proto_http }; + static constexpr int cons_len_exact = 16; + static constexpr unsigned short cons_tag[1] = { 0x4854 }; + struct Record { + typedef Protocol type_class; + }; + int get_size(const vm::CellSlice& cs) const override { + return 16; + } + bool skip(vm::CellSlice& cs) const override { + return cs.advance(16); + } + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; + bool fetch_enum_to(vm::CellSlice& cs, char& value) const; + bool store_enum_from(vm::CellBuilder& cb, int value) const; + bool unpack(vm::CellSlice& cs, Record& data) const; + bool unpack_proto_http(vm::CellSlice& cs) const; + bool cell_unpack(Ref cell_ref, Record& data) const; + bool cell_unpack_proto_http(Ref cell_ref) const; + bool pack(vm::CellBuilder& cb, const Record& data) const; + bool pack_proto_http(vm::CellBuilder& cb) const; + bool cell_pack(Ref& cell_ref, const Record& data) const; + bool cell_pack_proto_http(Ref& cell_ref) const; + bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override; + std::ostream& print_type(std::ostream& os) const override { + return os << "Protocol"; + } + int check_tag(const vm::CellSlice& cs) const override; + int get_tag(const vm::CellSlice& cs) const override { + return 0; + } +}; + +extern const Protocol t_Protocol; + +// +// headers for type `DNSRecord` +// + +struct DNSRecord final : TLB_Complex { + enum { dns_text, dns_smc_address, dns_adnl_address, dns_next_resolver }; + static constexpr int cons_len_exact = 16; + static constexpr unsigned short cons_tag[4] = { 0x1eda, 0x9fd3, 0xad01, 0xba93 }; + struct Record_dns_text { + typedef DNSRecord type_class; + Ref x; // Text + Record_dns_text() = default; + Record_dns_text(Ref _x) : x(std::move(_x)) {} + }; + struct Record_dns_next_resolver { + typedef DNSRecord type_class; + Ref resolver; // resolver : MsgAddressInt + Record_dns_next_resolver() = default; + Record_dns_next_resolver(Ref _resolver) : resolver(std::move(_resolver)) {} + }; + struct Record_dns_adnl_address; + struct Record_dns_smc_address; + bool skip(vm::CellSlice& cs) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; + bool unpack(vm::CellSlice& cs, Record_dns_text& data) const; + bool unpack_dns_text(vm::CellSlice& cs, Ref& x) const; + bool cell_unpack(Ref cell_ref, Record_dns_text& data) const; + bool cell_unpack_dns_text(Ref cell_ref, Ref& x) const; + bool pack(vm::CellBuilder& cb, const Record_dns_text& data) const; + bool pack_dns_text(vm::CellBuilder& cb, Ref x) const; + bool cell_pack(Ref& cell_ref, const Record_dns_text& data) const; + bool cell_pack_dns_text(Ref& cell_ref, Ref x) const; + bool unpack(vm::CellSlice& cs, Record_dns_next_resolver& data) const; + bool unpack_dns_next_resolver(vm::CellSlice& cs, Ref& resolver) const; + bool cell_unpack(Ref cell_ref, Record_dns_next_resolver& data) const; + bool cell_unpack_dns_next_resolver(Ref cell_ref, Ref& resolver) const; + bool pack(vm::CellBuilder& cb, const Record_dns_next_resolver& data) const; + bool pack_dns_next_resolver(vm::CellBuilder& cb, Ref resolver) const; + bool cell_pack(Ref& cell_ref, const Record_dns_next_resolver& data) const; + bool cell_pack_dns_next_resolver(Ref& cell_ref, Ref resolver) const; + bool unpack(vm::CellSlice& cs, Record_dns_adnl_address& data) const; + bool unpack_dns_adnl_address(vm::CellSlice& cs, td::BitArray<256>& adnl_addr, int& flags, Ref& proto_list) const; + bool cell_unpack(Ref cell_ref, Record_dns_adnl_address& data) const; + bool cell_unpack_dns_adnl_address(Ref cell_ref, td::BitArray<256>& adnl_addr, int& flags, Ref& proto_list) const; + bool pack(vm::CellBuilder& cb, const Record_dns_adnl_address& data) const; + bool pack_dns_adnl_address(vm::CellBuilder& cb, td::BitArray<256> adnl_addr, int flags, Ref proto_list) const; + bool cell_pack(Ref& cell_ref, const Record_dns_adnl_address& data) const; + bool cell_pack_dns_adnl_address(Ref& cell_ref, td::BitArray<256> adnl_addr, int flags, Ref proto_list) const; + bool unpack(vm::CellSlice& cs, Record_dns_smc_address& data) const; + bool unpack_dns_smc_address(vm::CellSlice& cs, Ref& smc_addr, int& flags, Ref& cap_list) const; + bool cell_unpack(Ref cell_ref, Record_dns_smc_address& data) const; + bool cell_unpack_dns_smc_address(Ref cell_ref, Ref& smc_addr, int& flags, Ref& cap_list) const; + bool pack(vm::CellBuilder& cb, const Record_dns_smc_address& data) const; + bool pack_dns_smc_address(vm::CellBuilder& cb, Ref smc_addr, int flags, Ref cap_list) const; + bool cell_pack(Ref& cell_ref, const Record_dns_smc_address& data) const; + bool cell_pack_dns_smc_address(Ref& cell_ref, Ref smc_addr, int flags, Ref cap_list) const; + bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override; + std::ostream& print_type(std::ostream& os) const override { + return os << "DNSRecord"; + } + int check_tag(const vm::CellSlice& cs) const override; + int get_tag(const vm::CellSlice& cs) const override { + return cs.bselect(4, 0xe02); + } +}; + +struct DNSRecord::Record_dns_adnl_address { + typedef DNSRecord type_class; + td::BitArray<256> adnl_addr; // adnl_addr : bits256 + int flags; // flags : ## 8 + Ref proto_list; // proto_list : flags.0?ProtoList + Record_dns_adnl_address() = default; + Record_dns_adnl_address(const td::BitArray<256>& _adnl_addr, int _flags, Ref _proto_list) : adnl_addr(_adnl_addr), flags(_flags), proto_list(std::move(_proto_list)) {} +}; + +struct DNSRecord::Record_dns_smc_address { + typedef DNSRecord type_class; + Ref smc_addr; // smc_addr : MsgAddressInt + int flags; // flags : ## 8 + Ref cap_list; // cap_list : flags.0?SmcCapList + Record_dns_smc_address() = default; + Record_dns_smc_address(Ref _smc_addr, int _flags, Ref _cap_list) : smc_addr(std::move(_smc_addr)), flags(_flags), cap_list(std::move(_cap_list)) {} +}; + +extern const DNSRecord t_DNSRecord; + +// +// headers for type `SmcCapList` +// + +struct SmcCapList final : TLB_Complex { + enum { cap_list_nil, cap_list_next }; + static constexpr int cons_len_exact = 1; + struct Record_cap_list_nil { + typedef SmcCapList type_class; + }; + struct Record_cap_list_next { + typedef SmcCapList type_class; + Ref head; // head : SmcCapability + Ref tail; // tail : SmcCapList + Record_cap_list_next() = default; + Record_cap_list_next(Ref _head, Ref _tail) : head(std::move(_head)), tail(std::move(_tail)) {} + }; + bool skip(vm::CellSlice& cs) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; + bool unpack(vm::CellSlice& cs, Record_cap_list_nil& data) const; + bool unpack_cap_list_nil(vm::CellSlice& cs) const; + bool cell_unpack(Ref cell_ref, Record_cap_list_nil& data) const; + bool cell_unpack_cap_list_nil(Ref cell_ref) const; + bool pack(vm::CellBuilder& cb, const Record_cap_list_nil& data) const; + bool pack_cap_list_nil(vm::CellBuilder& cb) const; + bool cell_pack(Ref& cell_ref, const Record_cap_list_nil& data) const; + bool cell_pack_cap_list_nil(Ref& cell_ref) const; + bool unpack(vm::CellSlice& cs, Record_cap_list_next& data) const; + bool unpack_cap_list_next(vm::CellSlice& cs, Ref& head, Ref& tail) const; + bool cell_unpack(Ref cell_ref, Record_cap_list_next& data) const; + bool cell_unpack_cap_list_next(Ref cell_ref, Ref& head, Ref& tail) const; + bool pack(vm::CellBuilder& cb, const Record_cap_list_next& data) const; + bool pack_cap_list_next(vm::CellBuilder& cb, Ref head, Ref tail) const; + bool cell_pack(Ref& cell_ref, const Record_cap_list_next& data) const; + bool cell_pack_cap_list_next(Ref& cell_ref, Ref head, Ref tail) const; + bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override; + std::ostream& print_type(std::ostream& os) const override { + return os << "SmcCapList"; + } + int check_tag(const vm::CellSlice& cs) const override; + int get_tag(const vm::CellSlice& cs) const override { + return (int)cs.prefetch_ulong(1); + } +}; + +extern const SmcCapList t_SmcCapList; + +// +// headers for type `SmcCapability` +// + +struct SmcCapability final : TLB_Complex { + enum { cap_is_wallet, cap_method_seqno, cap_method_pubkey, cap_name }; + static constexpr char cons_len[4] = { 16, 16, 16, 8 }; + static constexpr unsigned short cons_tag[4] = { 0x2177, 0x5371, 0x71f4, 0xff }; + struct Record_cap_method_seqno { + typedef SmcCapability type_class; + }; + struct Record_cap_method_pubkey { + typedef SmcCapability type_class; + }; + struct Record_cap_is_wallet { + typedef SmcCapability type_class; + }; + struct Record_cap_name { + typedef SmcCapability type_class; + Ref name; // name : Text + Record_cap_name() = default; + Record_cap_name(Ref _name) : name(std::move(_name)) {} + }; + bool skip(vm::CellSlice& cs) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; + bool unpack(vm::CellSlice& cs, Record_cap_method_seqno& data) const; + bool unpack_cap_method_seqno(vm::CellSlice& cs) const; + bool cell_unpack(Ref cell_ref, Record_cap_method_seqno& data) const; + bool cell_unpack_cap_method_seqno(Ref cell_ref) const; + bool pack(vm::CellBuilder& cb, const Record_cap_method_seqno& data) const; + bool pack_cap_method_seqno(vm::CellBuilder& cb) const; + bool cell_pack(Ref& cell_ref, const Record_cap_method_seqno& data) const; + bool cell_pack_cap_method_seqno(Ref& cell_ref) const; + bool unpack(vm::CellSlice& cs, Record_cap_method_pubkey& data) const; + bool unpack_cap_method_pubkey(vm::CellSlice& cs) const; + bool cell_unpack(Ref cell_ref, Record_cap_method_pubkey& data) const; + bool cell_unpack_cap_method_pubkey(Ref cell_ref) const; + bool pack(vm::CellBuilder& cb, const Record_cap_method_pubkey& data) const; + bool pack_cap_method_pubkey(vm::CellBuilder& cb) const; + bool cell_pack(Ref& cell_ref, const Record_cap_method_pubkey& data) const; + bool cell_pack_cap_method_pubkey(Ref& cell_ref) const; + bool unpack(vm::CellSlice& cs, Record_cap_is_wallet& data) const; + bool unpack_cap_is_wallet(vm::CellSlice& cs) const; + bool cell_unpack(Ref cell_ref, Record_cap_is_wallet& data) const; + bool cell_unpack_cap_is_wallet(Ref cell_ref) const; + bool pack(vm::CellBuilder& cb, const Record_cap_is_wallet& data) const; + bool pack_cap_is_wallet(vm::CellBuilder& cb) const; + bool cell_pack(Ref& cell_ref, const Record_cap_is_wallet& data) const; + bool cell_pack_cap_is_wallet(Ref& cell_ref) const; + bool unpack(vm::CellSlice& cs, Record_cap_name& data) const; + bool unpack_cap_name(vm::CellSlice& cs, Ref& name) const; + bool cell_unpack(Ref cell_ref, Record_cap_name& data) const; + bool cell_unpack_cap_name(Ref cell_ref, Ref& name) const; + bool pack(vm::CellBuilder& cb, const Record_cap_name& data) const; + bool pack_cap_name(vm::CellBuilder& cb, Ref name) const; + bool cell_pack(Ref& cell_ref, const Record_cap_name& data) const; + bool cell_pack_cap_name(Ref& cell_ref, Ref name) const; + bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override; + std::ostream& print_type(std::ostream& os) const override { + return os << "SmcCapability"; + } + int check_tag(const vm::CellSlice& cs) const override; + int get_tag(const vm::CellSlice& cs) const override { + return cs.bselect(3, 0x8e); + } +}; + +extern const SmcCapability t_SmcCapability; + // declarations of constant types used // ## 1 @@ -7367,6 +8638,8 @@ extern const NatWidth t_natwidth_8; extern const MessageRelaxed t_MessageRelaxed_Any; // ^(MessageRelaxed Any) extern const RefT t_Ref_MessageRelaxed_Any; +// ## 7 +extern const NatWidth t_natwidth_7; // #<= 60 extern const NatLeq t_natleq_60; // ^OutMsgQueueInfo @@ -7378,7 +8651,7 @@ extern const HashmapE t_HashmapE_256_LibDescr; // Maybe BlkMasterInfo extern const Maybe t_Maybe_BlkMasterInfo; // ^[$_ overload_history:uint64 underload_history:uint64 total_balance:CurrencyCollection total_validator_fees:CurrencyCollection libraries:(HashmapE 256 LibDescr) master_ref:(Maybe BlkMasterInfo) ] -extern const RefT t_Ref_TYPE_1637; +extern const RefT t_Ref_TYPE_1638; // ^McStateExtra extern const RefT t_Ref_McStateExtra; // Maybe ^McStateExtra @@ -7416,9 +8689,9 @@ extern const RefT t_Ref_McBlockExtra; // Maybe ^McBlockExtra extern const Maybe t_Maybe_Ref_McBlockExtra; // ^[$_ from_prev_blk:CurrencyCollection to_next_blk:CurrencyCollection imported:CurrencyCollection exported:CurrencyCollection ] -extern const RefT t_Ref_TYPE_1647; -// ^[$_ fees_imported:CurrencyCollection recovered:CurrencyCollection created:CurrencyCollection minted:CurrencyCollection ] extern const RefT t_Ref_TYPE_1648; +// ^[$_ fees_imported:CurrencyCollection recovered:CurrencyCollection created:CurrencyCollection minted:CurrencyCollection ] +extern const RefT t_Ref_TYPE_1649; // ## 3 extern const NatWidth t_natwidth_3; // BinTree ShardDescr @@ -7437,12 +8710,14 @@ extern const RefT t_Ref_Hashmap_32_Ref_Cell; extern const HashmapAugE t_HashmapAugE_32_KeyExtBlkRef_KeyMaxLt; // HashmapE 256 CreatorStats extern const HashmapE t_HashmapE_256_CreatorStats; +// HashmapAugE 256 CreatorStats uint32 +extern const HashmapAugE t_HashmapAugE_256_CreatorStats_uint32; // ## 16 extern const NatWidth t_natwidth_16; // Maybe ExtBlkRef extern const Maybe t_Maybe_ExtBlkRef; // ^[$_ flags:(## 16) {<= flags 1} validator_info:ValidatorInfo prev_blocks:OldMcBlocksInfo after_key_block:Bool last_key_block:(Maybe ExtBlkRef) block_create_stats:flags.0?BlockCreateStats ] -extern const RefT t_Ref_TYPE_1665; +extern const RefT t_Ref_TYPE_1666; // ^SignedCertificate extern const RefT t_Ref_SignedCertificate; // HashmapE 16 CryptoSignaturePair @@ -7450,7 +8725,7 @@ extern const HashmapE t_HashmapE_16_CryptoSignaturePair; // Maybe ^InMsg extern const Maybe t_Maybe_Ref_InMsg; // ^[$_ prev_blk_signatures:(HashmapE 16 CryptoSignaturePair) recover_create_msg:(Maybe ^InMsg) mint_msg:(Maybe ^InMsg) ] -extern const RefT t_Ref_TYPE_1673; +extern const RefT t_Ref_TYPE_1674; // Hashmap 16 ValidatorDescr extern const Hashmap t_Hashmap_16_ValidatorDescr; // HashmapE 16 ValidatorDescr @@ -7481,6 +8756,45 @@ extern const Maybe t_Maybe_Ref_BlockSignatures; extern const RefT t_Ref_TopBlockDescr; // HashmapE 96 ^TopBlockDescr extern const HashmapE t_HashmapE_96_Ref_TopBlockDescr; +// int64 +extern const Int t_int64; +// int257 +extern const Int t_int257; +// ## 10 +extern const NatWidth t_natwidth_10; +// #<= 4 +extern const NatLeq t_natleq_4; +// ^VmStackValue +extern const RefT t_Ref_VmStackValue; +// ## 24 +extern const NatWidth t_natwidth_24; +// HashmapE 4 VmStackValue +extern const HashmapE t_HashmapE_4_VmStackValue; +// ^[$_ max_limit:int64 cur_limit:int64 credit:int64 ] +extern const RefT t_Ref_TYPE_1705; +// HashmapE 256 ^Cell +extern const HashmapE t_HashmapE_256_Ref_Cell; +// uint13 +extern const UInt t_uint13; +// Maybe uint13 +extern const Maybe t_Maybe_uint13; +// Maybe VmStack +extern const Maybe t_Maybe_VmStack; +// int16 +extern const Int t_int16; +// Maybe int16 +extern const Maybe t_Maybe_int16; +// ^VmCont +extern const RefT t_Ref_VmCont; +// uint63 +extern const UInt t_uint63; +// ^DNSRecord +extern const RefT t_Ref_DNSRecord; +// HashmapE 16 ^DNSRecord +extern const HashmapE t_HashmapE_16_Ref_DNSRecord; + +// declaration of type name registration function +extern bool register_simple_types(std::function func); } // namespace gen diff --git a/submodules/ton/tonlib-src/crypto/block/block-parse.cpp b/submodules/ton/tonlib-src/crypto/block/block-parse.cpp index c410e2cb53..a032236608 100644 --- a/submodules/ton/tonlib-src/crypto/block/block-parse.cpp +++ b/submodules/ton/tonlib-src/crypto/block/block-parse.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "td/utils/bits.h" #include "block/block-parse.h" @@ -80,7 +80,7 @@ bool Maybe_Anycast::skip_get_depth(vm::CellSlice& cs, int& depth) const { const Maybe_Anycast t_Maybe_Anycast; -bool MsgAddressInt::validate_skip(vm::CellSlice& cs, bool weak) const { +bool MsgAddressInt::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { if (!cs.have(3)) { return false; } @@ -241,16 +241,38 @@ bool MsgAddressInt::extract_std_address(vm::CellSlice& cs, ton::WorkchainId& wor return false; } +bool MsgAddressInt::store_std_address(vm::CellBuilder& cb, ton::WorkchainId workchain, + const ton::StdSmcAddress& addr) const { + if (workchain >= -128 && workchain < 128) { + return cb.store_long_bool(4, 3) // addr_std$10 anycast:(Maybe Anycast) + && cb.store_long_bool(workchain, 8) // workchain_id:int8 + && cb.store_bits_bool(addr); // address:bits256 = MsgAddressInt; + } else { + return cb.store_long_bool(0xd00, 12) // addr_var$11 anycast:(Maybe Anycast) addr_len:(## 9) + && cb.store_long_bool(workchain, 32) // workchain_id:int32 + && cb.store_bits_bool(addr); // address:(bits addr_len) = MsgAddressInt; + } +} + +Ref MsgAddressInt::pack_std_address(ton::WorkchainId workchain, const ton::StdSmcAddress& addr) const { + vm::CellBuilder cb; + if (store_std_address(cb, workchain, addr)) { + return vm::load_cell_slice_ref(cb.finalize()); + } else { + return {}; + } +} + const MsgAddressInt t_MsgAddressInt; -bool MsgAddress::validate_skip(vm::CellSlice& cs, bool weak) const { +bool MsgAddress::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case addr_none: case addr_ext: - return t_MsgAddressExt.validate_skip(cs, weak); + return t_MsgAddressExt.validate_skip(ops, cs, weak); case addr_std: case addr_var: - return t_MsgAddressInt.validate_skip(cs, weak); + return t_MsgAddressInt.validate_skip(ops, cs, weak); } return false; } @@ -262,7 +284,7 @@ bool VarUInteger::skip(vm::CellSlice& cs) const { return len >= 0 && len < n && cs.advance(len * 8); } -bool VarUInteger::validate_skip(vm::CellSlice& cs, bool weak) const { +bool VarUInteger::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { int len = (int)cs.fetch_ulong(ln); return len >= 0 && len < n && (!len || cs.prefetch_ulong(8)) && cs.advance(len * 8); } @@ -303,7 +325,7 @@ bool VarUIntegerPos::skip(vm::CellSlice& cs) const { return len > 0 && len < n && cs.advance(len * 8); } -bool VarUIntegerPos::validate_skip(vm::CellSlice& cs, bool weak) const { +bool VarUIntegerPos::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { int len = (int)cs.fetch_ulong(ln); return len > 0 && len < n && cs.prefetch_ulong(8) && cs.advance(len * 8); } @@ -338,7 +360,7 @@ bool VarInteger::skip(vm::CellSlice& cs) const { return len >= 0 && len < n && cs.advance(len * 8); } -bool VarInteger::validate_skip(vm::CellSlice& cs, bool weak) const { +bool VarInteger::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { int len = (int)cs.fetch_ulong(ln); return len >= 0 && len < n && (!len || !redundant_int(cs)) && cs.advance(len * 8); } @@ -364,7 +386,7 @@ bool VarIntegerNz::skip(vm::CellSlice& cs) const { return len > 0 && len < n && cs.advance(len * 8); } -bool VarIntegerNz::validate_skip(vm::CellSlice& cs, bool weak) const { +bool VarIntegerNz::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { int len = (int)cs.fetch_ulong(ln); return len > 0 && len < n && !redundant_int(cs) && cs.advance(len * 8); } @@ -387,8 +409,8 @@ bool VarIntegerNz::store_integer_value(vm::CellBuilder& cb, const td::BigInt256& cb.store_int256_bool(value, (k + 7) & -8, true); } -bool Grams::validate_skip(vm::CellSlice& cs, bool weak) const { - return t_VarUInteger_16.validate_skip(cs, weak); +bool Grams::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_VarUInteger_16.validate_skip(ops, cs, weak); } td::RefInt256 Grams::as_integer_skip(vm::CellSlice& cs) const { @@ -442,15 +464,15 @@ bool HashmapNode::skip(vm::CellSlice& cs) const { return n ? cs.advance_refs(2) : value_type.skip(cs); } -bool HashmapNode::validate_skip(vm::CellSlice& cs, bool weak) const { +bool HashmapNode::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { assert(n >= 0); if (!n) { // hmn_leaf - return value_type.validate_skip(cs, weak); + return value_type.validate_skip(ops, cs, weak); } else { // hmn_fork Hashmap branch_type{n - 1, value_type}; - return branch_type.validate_ref(cs.fetch_ref(), weak) && branch_type.validate_ref(cs.fetch_ref(), weak); + return branch_type.validate_ref(ops, cs.fetch_ref(), weak) && branch_type.validate_ref(ops, cs.fetch_ref(), weak); } } @@ -459,9 +481,9 @@ bool Hashmap::skip(vm::CellSlice& cs) const { return HmLabel{n}.skip(cs, l) && HashmapNode{n - l, value_type}.skip(cs); } -bool Hashmap::validate_skip(vm::CellSlice& cs, bool weak) const { +bool Hashmap::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { int l; - return HmLabel{n}.validate_skip(cs, weak, l) && HashmapNode{n - l, value_type}.validate_skip(cs, weak); + return HmLabel{n}.validate_skip(cs, weak, l) && HashmapNode{n - l, value_type}.validate_skip(ops, cs, weak); } int HashmapE::get_size(const vm::CellSlice& cs) const { @@ -469,9 +491,9 @@ int HashmapE::get_size(const vm::CellSlice& cs) const { return (tag >= 0 ? (tag > 0 ? 0x10001 : 1) : -1); } -bool HashmapE::validate(const vm::CellSlice& cs, bool weak) const { +bool HashmapE::validate(int* ops, const vm::CellSlice& cs, bool weak) const { int tag = get_tag(cs); - return tag <= 0 ? !tag : root_type.validate_ref(cs.prefetch_ref(), weak); + return tag <= 0 ? !tag : root_type.validate_ref(ops, cs.prefetch_ref(), weak); } bool HashmapE::add_values(vm::CellBuilder& cb, vm::CellSlice& cs1, vm::CellSlice& cs2) const { @@ -561,8 +583,8 @@ bool HashmapE::store_ref(vm::CellBuilder& cb, Ref arg) const { const ExtraCurrencyCollection t_ExtraCurrencyCollection; -bool CurrencyCollection::validate_skip(vm::CellSlice& cs, bool weak) const { - return t_Grams.validate_skip(cs, weak) && t_ExtraCurrencyCollection.validate_skip(cs, weak); +bool CurrencyCollection::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_Grams.validate_skip(ops, cs, weak) && t_ExtraCurrencyCollection.validate_skip(ops, cs, weak); } bool CurrencyCollection::skip(vm::CellSlice& cs) const { @@ -619,25 +641,25 @@ bool CurrencyCollection::pack(vm::CellBuilder& cb, const block::CurrencyCollecti const CurrencyCollection t_CurrencyCollection; -bool CommonMsgInfo::validate_skip(vm::CellSlice& cs, bool weak) const { +bool CommonMsgInfo::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { int tag = get_tag(cs); switch (tag) { case int_msg_info: - return cs.advance(4) // int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool - && t_MsgAddressInt.validate_skip(cs, weak) // src - && t_MsgAddressInt.validate_skip(cs, weak) // dest - && t_CurrencyCollection.validate_skip(cs, weak) // value - && t_Grams.validate_skip(cs, weak) // ihr_fee - && t_Grams.validate_skip(cs, weak) // fwd_fee - && cs.advance(64 + 32); // created_lt:uint64 created_at:uint32 + return cs.advance(4) // int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool + && t_MsgAddressInt.validate_skip(ops, cs, weak) // src + && t_MsgAddressInt.validate_skip(ops, cs, weak) // dest + && t_CurrencyCollection.validate_skip(ops, cs, weak) // value + && t_Grams.validate_skip(ops, cs, weak) // ihr_fee + && t_Grams.validate_skip(ops, cs, weak) // fwd_fee + && cs.advance(64 + 32); // created_lt:uint64 created_at:uint32 case ext_in_msg_info: - return cs.advance(2) && t_MsgAddressExt.validate_skip(cs, weak) // src - && t_MsgAddressInt.validate_skip(cs, weak) // dest - && t_Grams.validate_skip(cs, weak); // import_fee + return cs.advance(2) && t_MsgAddressExt.validate_skip(ops, cs, weak) // src + && t_MsgAddressInt.validate_skip(ops, cs, weak) // dest + && t_Grams.validate_skip(ops, cs, weak); // import_fee case ext_out_msg_info: - return cs.advance(2) && t_MsgAddressInt.validate_skip(cs, weak) // src - && t_MsgAddressExt.validate_skip(cs, weak) // dest - && cs.advance(64 + 32); // created_lt:uint64 created_at:uint32 + return cs.advance(2) && t_MsgAddressInt.validate_skip(ops, cs, weak) // src + && t_MsgAddressExt.validate_skip(ops, cs, weak) // dest + && cs.advance(64 + 32); // created_lt:uint64 created_at:uint32 } return false; } @@ -699,28 +721,29 @@ const CommonMsgInfo t_CommonMsgInfo; const TickTock t_TickTock; const RefAnything t_RefCell; -bool StateInit::validate_skip(vm::CellSlice& cs, bool weak) const { - return Maybe{5}.validate_skip(cs, weak) // split_depth:(Maybe (## 5)) - && Maybe{}.validate_skip(cs, weak) // special:(Maybe TickTock) - && Maybe{}.validate_skip(cs, weak) // code:(Maybe ^Cell) - && Maybe{}.validate_skip(cs, weak) // data:(Maybe ^Cell) - && Maybe{}.validate_skip(cs, weak); // library:(Maybe ^Cell) +bool StateInit::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return Maybe{5}.validate_skip(ops, cs, weak) // split_depth:(Maybe (## 5)) + && Maybe{}.validate_skip(ops, cs, weak) // special:(Maybe TickTock) + && Maybe{}.validate_skip(ops, cs, weak) // code:(Maybe ^Cell) + && Maybe{}.validate_skip(ops, cs, weak) // data:(Maybe ^Cell) + && Maybe{}.validate_skip(ops, cs, weak); // library:(Maybe ^Cell) } bool StateInit::get_ticktock(vm::CellSlice& cs, int& ticktock) const { bool have_tt; ticktock = 0; - return Maybe{5}.validate_skip(cs) && cs.fetch_bool_to(have_tt) && (!have_tt || cs.fetch_uint_to(2, ticktock)); + return Maybe{5}.validate_skip_upto(1, cs) && cs.fetch_bool_to(have_tt) && + (!have_tt || cs.fetch_uint_to(2, ticktock)); } const StateInit t_StateInit; -bool Message::validate_skip(vm::CellSlice& cs, bool weak) const { +bool Message::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { static const Maybe>> init_type; static const Either body_type; - return t_CommonMsgInfo.validate_skip(cs, weak) // info:CommonMsgInfo - && init_type.validate_skip(cs, weak) // init:(Maybe (Either StateInit ^StateInit)) - && body_type.validate_skip(cs, weak); // body:(Either X ^X) + return t_CommonMsgInfo.validate_skip(ops, cs, weak) // info:CommonMsgInfo + && init_type.validate_skip(ops, cs, weak) // init:(Maybe (Either StateInit ^StateInit)) + && body_type.validate_skip(ops, cs, weak); // body:(Either X ^X) } bool Message::extract_info(vm::CellSlice& cs) const { @@ -738,7 +761,7 @@ bool Message::is_internal(Ref ref) const { const Message t_Message; const RefTo t_Ref_Message; -bool IntermediateAddress::validate_skip(vm::CellSlice& cs, bool weak) const { +bool IntermediateAddress::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case interm_addr_regular: return cs.advance(1) && cs.fetch_ulong(7) <= 96U; @@ -773,12 +796,12 @@ int IntermediateAddress::get_size(const vm::CellSlice& cs) const { const IntermediateAddress t_IntermediateAddress; -bool MsgEnvelope::validate_skip(vm::CellSlice& cs, bool weak) const { - return cs.fetch_ulong(4) == 4 // msg_envelope#4 - && t_IntermediateAddress.validate_skip(cs, weak) // cur_addr:IntermediateAddress - && t_IntermediateAddress.validate_skip(cs, weak) // next_addr:IntermediateAddress - && t_Grams.validate_skip(cs, weak) // fwd_fee_remaining:Grams - && t_Ref_Message.validate_skip(cs, weak); // msg:^Message +bool MsgEnvelope::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return cs.fetch_ulong(4) == 4 // msg_envelope#4 + && t_IntermediateAddress.validate_skip(ops, cs, weak) // cur_addr:IntermediateAddress + && t_IntermediateAddress.validate_skip(ops, cs, weak) // next_addr:IntermediateAddress + && t_Grams.validate_skip(ops, cs, weak) // fwd_fee_remaining:Grams + && t_Ref_Message.validate_skip(ops, cs, weak); // msg:^Message } bool MsgEnvelope::skip(vm::CellSlice& cs) const { @@ -827,10 +850,10 @@ bool MsgEnvelope::get_created_lt(const vm::CellSlice& cs, unsigned long long& cr const MsgEnvelope t_MsgEnvelope; const RefTo t_Ref_MsgEnvelope; -bool StorageUsed::validate_skip(vm::CellSlice& cs, bool weak) const { - return t_VarUInteger_7.validate_skip(cs, weak) // cells:(VarUInteger 7) - && t_VarUInteger_7.validate_skip(cs, weak) // bits:(VarUInteger 7) - && t_VarUInteger_7.validate_skip(cs, weak); // public_cells:(VarUInteger 7) +bool StorageUsed::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_VarUInteger_7.validate_skip(ops, cs, weak) // cells:(VarUInteger 7) + && t_VarUInteger_7.validate_skip(ops, cs, weak) // bits:(VarUInteger 7) + && t_VarUInteger_7.validate_skip(ops, cs, weak); // public_cells:(VarUInteger 7) } bool StorageUsed::skip(vm::CellSlice& cs) const { @@ -841,9 +864,9 @@ bool StorageUsed::skip(vm::CellSlice& cs) const { const StorageUsed t_StorageUsed; -bool StorageUsedShort::validate_skip(vm::CellSlice& cs, bool weak) const { - return t_VarUInteger_7.validate_skip(cs, weak) // cells:(VarUInteger 7) - && t_VarUInteger_7.validate_skip(cs, weak); // bits:(VarUInteger 7) +bool StorageUsedShort::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_VarUInteger_7.validate_skip(ops, cs, weak) // cells:(VarUInteger 7) + && t_VarUInteger_7.validate_skip(ops, cs, weak); // bits:(VarUInteger 7) } bool StorageUsedShort::skip(vm::CellSlice& cs) const { @@ -861,22 +884,22 @@ bool StorageInfo::skip(vm::CellSlice& cs) const { && t_Maybe_Grams.skip(cs); // due_payment:(Maybe Grams) } -bool StorageInfo::validate_skip(vm::CellSlice& cs, bool weak) const { - return t_StorageUsed.validate_skip(cs, weak) // used:StorageUsed - && cs.advance(32) // last_paid:uint32 - && t_Maybe_Grams.validate_skip(cs, weak); // due_payment:(Maybe Grams) +bool StorageInfo::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_StorageUsed.validate_skip(ops, cs, weak) // used:StorageUsed + && cs.advance(32) // last_paid:uint32 + && t_Maybe_Grams.validate_skip(ops, cs, weak); // due_payment:(Maybe Grams) } const StorageInfo t_StorageInfo; -bool AccountState::validate_skip(vm::CellSlice& cs, bool weak) const { +bool AccountState::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case account_uninit: return cs.advance(2); case account_frozen: return cs.advance(2 + 256); case account_active: - return cs.advance(1) && t_StateInit.validate_skip(cs, weak); + return cs.advance(1) && t_StateInit.validate_skip(ops, cs, weak); } return false; } @@ -899,8 +922,9 @@ bool AccountStorage::skip_copy_balance(vm::CellBuilder& cb, vm::CellSlice& cs) c return cs.advance(64) && t_CurrencyCollection.skip_copy(cb, cs) && t_AccountState.skip(cs); } -bool AccountStorage::validate_skip(vm::CellSlice& cs, bool weak) const { - return cs.advance(64) && t_CurrencyCollection.validate_skip(cs, weak) && t_AccountState.validate_skip(cs, weak); +bool AccountStorage::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return cs.advance(64) && t_CurrencyCollection.validate_skip(ops, cs, weak) && + t_AccountState.validate_skip(ops, cs, weak); } const AccountStorage t_AccountStorage; @@ -918,15 +942,15 @@ bool Account::skip(vm::CellSlice& cs) const { return false; } -bool Account::validate_skip(vm::CellSlice& cs, bool weak) const { +bool Account::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case account_none: return allow_empty && cs.advance(1); case account: - return cs.advance(1) // account$1 - && t_MsgAddressInt.validate_skip(cs, weak) // addr:MsgAddressInt - && t_StorageInfo.validate_skip(cs, weak) // storage_stat:StorageInfo - && t_AccountStorage.validate_skip(cs, weak); // storage:AccountStorage + return cs.advance(1) // account$1 + && t_MsgAddressInt.validate_skip(ops, cs, weak) // addr:MsgAddressInt + && t_StorageInfo.validate_skip(ops, cs, weak) // storage_stat:StorageInfo + && t_AccountStorage.validate_skip(ops, cs, weak); // storage:AccountStorage } return false; } @@ -1010,19 +1034,19 @@ bool HashmapAugNode::skip(vm::CellSlice& cs) const { } } -bool HashmapAugNode::validate_skip(vm::CellSlice& cs, bool weak) const { +bool HashmapAugNode::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { if (n < 0) { return false; } if (!n) { // ahmn_leaf vm::CellSlice cs_extra{cs}; - if (!aug.extra_type.validate_skip(cs, weak)) { + if (!aug.extra_type.validate_skip(ops, cs, weak)) { return false; } cs_extra.cut_tail(cs); vm::CellSlice cs_value{cs}; - if (!aug.value_type.validate_skip(cs, weak)) { + if (!aug.value_type.validate_skip(ops, cs, weak)) { return false; } cs_value.cut_tail(cs); @@ -1033,13 +1057,14 @@ bool HashmapAugNode::validate_skip(vm::CellSlice& cs, bool weak) const { return false; } HashmapAug branch_type{n - 1, aug}; - if (!branch_type.validate_ref(cs.prefetch_ref(0), weak) || !branch_type.validate_ref(cs.prefetch_ref(1), weak)) { + if (!branch_type.validate_ref(ops, cs.prefetch_ref(0), weak) || + !branch_type.validate_ref(ops, cs.prefetch_ref(1), weak)) { return false; } auto cs_left = load_cell_slice(cs.fetch_ref()); auto cs_right = load_cell_slice(cs.fetch_ref()); vm::CellSlice cs_extra{cs}; - if (!aug.extra_type.validate_skip(cs, weak)) { + if (!aug.extra_type.validate_skip(ops, cs, weak)) { return false; } cs_extra.cut_tail(cs); @@ -1052,9 +1077,9 @@ bool HashmapAug::skip(vm::CellSlice& cs) const { return HmLabel{n}.skip(cs, l) && HashmapAugNode{n - l, aug}.skip(cs); } -bool HashmapAug::validate_skip(vm::CellSlice& cs, bool weak) const { +bool HashmapAug::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { int l; - return HmLabel{n}.validate_skip(cs, weak, l) && HashmapAugNode{n - l, aug}.validate_skip(cs, weak); + return HmLabel{n}.validate_skip(cs, weak, l) && HashmapAugNode{n - l, aug}.validate_skip(ops, cs, weak); } bool HashmapAug::extract_extra(vm::CellSlice& cs) const { @@ -1062,20 +1087,20 @@ bool HashmapAug::extract_extra(vm::CellSlice& cs) const { return HmLabel{n}.skip(cs, l) && (l == n || cs.advance_refs(2)) && aug.extra_type.extract(cs); } -bool HashmapAugE::validate_skip(vm::CellSlice& cs, bool weak) const { +bool HashmapAugE::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { Ref extra; switch (get_tag(cs)) { case ahme_empty: - return cs.advance(1) && (extra = root_type.aug.extra_type.validate_fetch(cs, weak)).not_null() && + return cs.advance(1) && (extra = root_type.aug.extra_type.validate_fetch(ops, cs, weak)).not_null() && root_type.aug.check_empty(extra.unique_write()); case ahme_root: - if (cs.advance(1) && root_type.validate_ref(cs.prefetch_ref(), weak)) { + if (cs.advance(1) && root_type.validate_ref(ops, cs.prefetch_ref(), weak)) { bool special; auto cs_root = load_cell_slice_special(cs.fetch_ref(), special); if (special) { return weak; } - return (extra = root_type.aug.extra_type.validate_fetch(cs, weak)).not_null() && + return (extra = root_type.aug.extra_type.validate_fetch(ops, cs, weak)).not_null() && root_type.extract_extra(cs_root) && extra->contents_equal(cs_root); } break; @@ -1099,9 +1124,10 @@ bool DepthBalanceInfo::skip(vm::CellSlice& cs) const { cs); // depth_balance$_ split_depth:(#<= 30) balance:CurrencyCollection = DepthBalanceInfo; } -bool DepthBalanceInfo::validate_skip(vm::CellSlice& cs, bool weak) const { - return cs.fetch_ulong(5) <= 30 && t_CurrencyCollection.validate_skip( - cs, weak); // depth_balance$_ split_depth:(#<= 30) balance:CurrencyCollection +bool DepthBalanceInfo::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return cs.fetch_ulong(5) <= 30 && + t_CurrencyCollection.validate_skip(ops, cs, + weak); // depth_balance$_ split_depth:(#<= 30) balance:CurrencyCollection } bool DepthBalanceInfo::null_value(vm::CellBuilder& cb) const { @@ -1137,10 +1163,10 @@ bool TrStoragePhase::skip(vm::CellSlice& cs) const { && t_AccStatusChange.skip(cs); // status_change:AccStatusChange } -bool TrStoragePhase::validate_skip(vm::CellSlice& cs, bool weak) const { - return t_Grams.validate_skip(cs, weak) // storage_fees_collected:Grams - && t_Maybe_Grams.validate_skip(cs, weak) // storage_fees_due:Grams - && t_AccStatusChange.validate_skip(cs, weak); // status_change:AccStatusChange +bool TrStoragePhase::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_Grams.validate_skip(ops, cs, weak) // storage_fees_collected:Grams + && t_Maybe_Grams.validate_skip(ops, cs, weak) // storage_fees_due:Grams + && t_AccStatusChange.validate_skip(ops, cs, weak); // status_change:AccStatusChange } bool TrStoragePhase::get_storage_fees(vm::CellSlice& cs, td::RefInt256& storage_fees) const { @@ -1164,9 +1190,9 @@ bool TrCreditPhase::skip(vm::CellSlice& cs) const { && t_CurrencyCollection.skip(cs); // credit:CurrencyCollection } -bool TrCreditPhase::validate_skip(vm::CellSlice& cs, bool weak) const { - return t_Maybe_Grams.validate_skip(cs, weak) // due_fees_collected:(Maybe Grams) - && t_CurrencyCollection.validate_skip(cs, weak); // credit:CurrencyCollection +bool TrCreditPhase::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_Maybe_Grams.validate_skip(ops, cs, weak) // due_fees_collected:(Maybe Grams) + && t_CurrencyCollection.validate_skip(ops, cs, weak); // credit:CurrencyCollection } const TrCreditPhase t_TrCreditPhase; @@ -1182,15 +1208,15 @@ bool TrComputeInternal1::skip(vm::CellSlice& cs) const { // vm_final_state_hash:uint256 } -bool TrComputeInternal1::validate_skip(vm::CellSlice& cs, bool weak) const { - return t_VarUInteger_7.validate_skip(cs, weak) // gas_used:(VarUInteger 7) - && t_VarUInteger_7.validate_skip(cs, weak) // gas_limit:(VarUInteger 7) - && Maybe{3}.validate_skip(cs, weak) // gas_credit:(Maybe (VarUInteger 3)) - && cs.advance(8 + 32) // mode:int8 exit_code:int32 - && Maybe{32}.validate_skip(cs, weak) // exit_arg:(Maybe int32) - && cs.advance(32 + 256 + 256); // vm_steps:uint32 - // vm_init_state_hash:uint256 - // vm_final_state_hash:uint256 +bool TrComputeInternal1::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_VarUInteger_7.validate_skip(ops, cs, weak) // gas_used:(VarUInteger 7) + && t_VarUInteger_7.validate_skip(ops, cs, weak) // gas_limit:(VarUInteger 7) + && Maybe{3}.validate_skip(ops, cs, weak) // gas_credit:(Maybe (VarUInteger 3)) + && cs.advance(8 + 32) // mode:int8 exit_code:int32 + && Maybe{32}.validate_skip(ops, cs, weak) // exit_arg:(Maybe int32) + && cs.advance(32 + 256 + 256); // vm_steps:uint32 + // vm_init_state_hash:uint256 + // vm_final_state_hash:uint256 } const TrComputeInternal1 t_TrComputeInternal1; @@ -1209,14 +1235,14 @@ bool TrComputePhase::skip(vm::CellSlice& cs) const { return false; } -bool TrComputePhase::validate_skip(vm::CellSlice& cs, bool weak) const { +bool TrComputePhase::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case tr_phase_compute_skipped: - return cs.advance(1) && t_ComputeSkipReason.validate_skip(cs, weak); + return cs.advance(1) && t_ComputeSkipReason.validate_skip(ops, cs, weak); case tr_phase_compute_vm: return cs.advance(1 + 3) // tr_phase_compute_vm$1 success:Bool msg_state_used:Bool account_activated:Bool - && t_Grams.validate_skip(cs, weak) // gas_fees:Grams - && t_Ref_TrComputeInternal1.validate_skip(cs, weak); // ^[ gas_used:(..) .. ] + && t_Grams.validate_skip(ops, cs, weak) // gas_fees:Grams + && t_Ref_TrComputeInternal1.validate_skip(ops, cs, weak); // ^[ gas_used:(..) .. ] } return false; } @@ -1236,17 +1262,17 @@ bool TrActionPhase::skip(vm::CellSlice& cs) const { && t_StorageUsedShort.skip(cs); // tot_msg_size:StorageUsedShort } -bool TrActionPhase::validate_skip(vm::CellSlice& cs, bool weak) const { - return cs.advance(3) // success:Bool valid:Bool no_funds:Bool - && t_AccStatusChange.validate_skip(cs, weak) // status_change:AccStatusChange - && t_Maybe_Grams.validate_skip(cs, weak) // total_fwd_fees:(Maybe Grams) - && t_Maybe_Grams.validate_skip(cs, weak) // total_action_fees:(Maybe Grams) - && cs.advance(32) // result_code:int32 - && Maybe{32}.validate_skip(cs, weak) // result_arg:(Maybe int32) - && cs.advance(16 * 4 + 256) // tot_actions:uint16 spec_actions:uint16 - // skipped_actions:uint16 msgs_created:uint16 - // action_list_hash:uint256 - && t_StorageUsedShort.validate_skip(cs, weak); // tot_msg_size:StorageUsed +bool TrActionPhase::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return cs.advance(3) // success:Bool valid:Bool no_funds:Bool + && t_AccStatusChange.validate_skip(ops, cs, weak) // status_change:AccStatusChange + && t_Maybe_Grams.validate_skip(ops, cs, weak) // total_fwd_fees:(Maybe Grams) + && t_Maybe_Grams.validate_skip(ops, cs, weak) // total_action_fees:(Maybe Grams) + && cs.advance(32) // result_code:int32 + && Maybe{32}.validate_skip(ops, cs, weak) // result_arg:(Maybe int32) + && cs.advance(16 * 4 + 256) // tot_actions:uint16 spec_actions:uint16 + // skipped_actions:uint16 msgs_created:uint16 + // action_list_hash:uint256 + && t_StorageUsedShort.validate_skip(ops, cs, weak); // tot_msg_size:StorageUsed } const TrActionPhase t_TrActionPhase; @@ -1268,19 +1294,19 @@ bool TrBouncePhase::skip(vm::CellSlice& cs) const { return false; } -bool TrBouncePhase::validate_skip(vm::CellSlice& cs, bool weak) const { +bool TrBouncePhase::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case tr_phase_bounce_negfunds: return cs.advance(2); // tr_phase_bounce_negfunds$00 case tr_phase_bounce_nofunds: - return cs.advance(2) // tr_phase_bounce_nofunds$01 - && t_StorageUsedShort.validate_skip(cs, weak) // msg_size:StorageUsedShort - && t_Grams.validate_skip(cs, weak); // req_fwd_fees:Grams + return cs.advance(2) // tr_phase_bounce_nofunds$01 + && t_StorageUsedShort.validate_skip(ops, cs, weak) // msg_size:StorageUsedShort + && t_Grams.validate_skip(ops, cs, weak); // req_fwd_fees:Grams case tr_phase_bounce_ok: - return cs.advance(1) // tr_phase_bounce_ok$1 - && t_StorageUsedShort.validate_skip(cs, weak) // msg_size:StorageUsedShort - && t_Grams.validate_skip(cs, weak) // msg_fees:Grams - && t_Grams.validate_skip(cs, weak); // fwd_fees:Grams + return cs.advance(1) // tr_phase_bounce_ok$1 + && t_StorageUsedShort.validate_skip(ops, cs, weak) // msg_size:StorageUsedShort + && t_Grams.validate_skip(ops, cs, weak) // msg_fees:Grams + && t_Grams.validate_skip(ops, cs, weak); // fwd_fees:Grams } return false; } @@ -1300,7 +1326,7 @@ bool SplitMergeInfo::skip(vm::CellSlice& cs) const { return cs.advance(6 + 6 + 256 + 256); } -bool SplitMergeInfo::validate_skip(vm::CellSlice& cs, bool weak) const { +bool SplitMergeInfo::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { if (!cs.have(6 + 6 + 256 + 256)) { return false; } @@ -1370,52 +1396,52 @@ bool TransactionDescr::skip(vm::CellSlice& cs) const { return false; } -bool TransactionDescr::validate_skip(vm::CellSlice& cs, bool weak) const { +bool TransactionDescr::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case trans_ord: - return cs.advance(4 + 1) // trans_ord$0000 credit_first:Bool - && Maybe{}.validate_skip(cs, weak) // storage_ph:(Maybe TrStoragePhase) - && Maybe{}.validate_skip(cs, weak) // credit_ph:(Maybe TrCreditPhase) - && t_TrComputePhase.validate_skip(cs, weak) // compute_ph:TrComputePhase - && Maybe>{}.validate_skip(cs, weak) // action:(Maybe ^TrActionPhase) - && cs.advance(1) // aborted:Bool - && Maybe{}.validate_skip(cs, weak) // bounce:(Maybe TrBouncePhase) - && cs.advance(1); // destroyed:Bool + return cs.advance(4 + 1) // trans_ord$0000 credit_first:Bool + && Maybe{}.validate_skip(ops, cs, weak) // storage_ph:(Maybe TrStoragePhase) + && Maybe{}.validate_skip(ops, cs, weak) // credit_ph:(Maybe TrCreditPhase) + && t_TrComputePhase.validate_skip(ops, cs, weak) // compute_ph:TrComputePhase + && Maybe>{}.validate_skip(ops, cs, weak) // action:(Maybe ^TrActionPhase) + && cs.advance(1) // aborted:Bool + && Maybe{}.validate_skip(ops, cs, weak) // bounce:(Maybe TrBouncePhase) + && cs.advance(1); // destroyed:Bool case trans_storage: - return cs.advance(4) // trans_storage$0001 - && t_TrStoragePhase.validate_skip(cs, weak); // storage_ph:TrStoragePhase + return cs.advance(4) // trans_storage$0001 + && t_TrStoragePhase.validate_skip(ops, cs, weak); // storage_ph:TrStoragePhase case trans_tick_tock: - return cs.advance(4) // trans_tick_tock$001 is_tock:Bool - && t_TrStoragePhase.validate_skip(cs, weak) // storage_ph:TrStoragePhase - && t_TrComputePhase.validate_skip(cs, weak) // compute_ph:TrComputePhase - && Maybe>{}.validate_skip(cs, weak) // action:(Maybe ^TrActionPhase) - && cs.advance(2); // aborted:Bool destroyed:Bool + return cs.advance(4) // trans_tick_tock$001 is_tock:Bool + && t_TrStoragePhase.validate_skip(ops, cs, weak) // storage_ph:TrStoragePhase + && t_TrComputePhase.validate_skip(ops, cs, weak) // compute_ph:TrComputePhase + && Maybe>{}.validate_skip(ops, cs, weak) // action:(Maybe ^TrActionPhase) + && cs.advance(2); // aborted:Bool destroyed:Bool case trans_split_prepare: - return cs.advance(4) // trans_split_prepare$0100 - && t_SplitMergeInfo.validate_skip(cs, weak) // split_info:SplitMergeInfo - && Maybe{}.validate_skip(cs, weak) // storage_ph:(Maybe TrStoragePhase) - && t_TrComputePhase.validate_skip(cs, weak) // compute_ph:TrComputePhase - && Maybe>{}.validate_skip(cs, weak) // action:(Maybe ^TrActionPhase) - && cs.advance(2); // aborted:Bool destroyed:Bool + return cs.advance(4) // trans_split_prepare$0100 + && t_SplitMergeInfo.validate_skip(ops, cs, weak) // split_info:SplitMergeInfo + && Maybe{}.validate_skip(ops, cs, weak) // storage_ph:(Maybe TrStoragePhase) + && t_TrComputePhase.validate_skip(ops, cs, weak) // compute_ph:TrComputePhase + && Maybe>{}.validate_skip(ops, cs, weak) // action:(Maybe ^TrActionPhase) + && cs.advance(2); // aborted:Bool destroyed:Bool case trans_split_install: - return cs.advance(4) // trans_split_install$0101 - && t_SplitMergeInfo.validate_skip(cs, weak) // split_info:SplitMergeInfo - && t_Ref_Transaction.validate_skip(cs, weak) // prepare_transaction:^Transaction - && cs.advance(1); // installed:Bool + return cs.advance(4) // trans_split_install$0101 + && t_SplitMergeInfo.validate_skip(ops, cs, weak) // split_info:SplitMergeInfo + && t_Ref_Transaction.validate_skip(ops, cs, weak) // prepare_transaction:^Transaction + && cs.advance(1); // installed:Bool case trans_merge_prepare: - return cs.advance(4) // trans_merge_prepare$0110 - && t_SplitMergeInfo.validate_skip(cs, weak) // split_info:SplitMergeInfo - && t_TrStoragePhase.validate_skip(cs, weak) // storage_ph:TrStoragePhase - && cs.advance(1); // aborted:Bool + return cs.advance(4) // trans_merge_prepare$0110 + && t_SplitMergeInfo.validate_skip(ops, cs, weak) // split_info:SplitMergeInfo + && t_TrStoragePhase.validate_skip(ops, cs, weak) // storage_ph:TrStoragePhase + && cs.advance(1); // aborted:Bool case trans_merge_install: - return cs.advance(4) // trans_merge_install$0111 - && t_SplitMergeInfo.validate_skip(cs, weak) // split_info:SplitMergeInfo - && t_Ref_Transaction.validate_skip(cs, weak) // prepare_transaction:^Transaction - && Maybe{}.validate_skip(cs, weak) // storage_ph:(Maybe TrStoragePhase) - && Maybe{}.validate_skip(cs, weak) // credit_ph:(Maybe TrCreditPhase) - && Maybe{}.validate_skip(cs, weak) // compute_ph:TrComputePhase - && Maybe>{}.validate_skip(cs, weak) // action:(Maybe ^TrActionPhase) - && cs.advance(2); // aborted:Bool destroyed:Bool + return cs.advance(4) // trans_merge_install$0111 + && t_SplitMergeInfo.validate_skip(ops, cs, weak) // split_info:SplitMergeInfo + && t_Ref_Transaction.validate_skip(ops, cs, weak) // prepare_transaction:^Transaction + && Maybe{}.validate_skip(ops, cs, weak) // storage_ph:(Maybe TrStoragePhase) + && Maybe{}.validate_skip(ops, cs, weak) // credit_ph:(Maybe TrCreditPhase) + && Maybe{}.validate_skip(ops, cs, weak) // compute_ph:TrComputePhase + && Maybe>{}.validate_skip(ops, cs, weak) // action:(Maybe ^TrActionPhase) + && cs.advance(2); // aborted:Bool destroyed:Bool } return false; } @@ -1479,9 +1505,9 @@ bool Transaction_aux::skip(vm::CellSlice& cs) const { && HashmapE{15, t_Ref_Message}.skip(cs); // out_msgs:(HashmapE 15 ^Message) } -bool Transaction_aux::validate_skip(vm::CellSlice& cs, bool weak) const { - return Maybe>{}.validate_skip(cs, weak) // in_msg:(Maybe ^Message) - && HashmapE{15, t_Ref_Message}.validate_skip(cs, weak); // out_msgs:(HashmapE 15 ^Message) +bool Transaction_aux::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return Maybe>{}.validate_skip(ops, cs, weak) // in_msg:(Maybe ^Message) + && HashmapE{15, t_Ref_Message}.validate_skip(ops, cs, weak); // out_msgs:(HashmapE 15 ^Message) } const Transaction_aux t_Transaction_aux; @@ -1498,18 +1524,18 @@ bool Transaction::skip(vm::CellSlice& cs) const { && RefTo{}.skip(cs); // description:^TransactionDescr } -bool Transaction::validate_skip(vm::CellSlice& cs, bool weak) const { +bool Transaction::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { return cs.fetch_ulong(4) == 7 // transaction$0111 && cs.advance( 256 + 64 + 256 + 64 + 32 + 15) // account_addr:uint256 lt:uint64 prev_trans_hash:bits256 prev_trans_lt:uint64 now:uint32 outmsg_cnt:uint15 - && t_AccountStatus.validate_skip(cs, weak) // orig_status:AccountStatus - && t_AccountStatus.validate_skip(cs, weak) // end_status:AccountStatus - && RefTo{}.validate_skip(cs, weak) // ^[ in_msg:... out_msgs:... ] - && t_CurrencyCollection.validate_skip(cs, weak) // total_fees:CurrencyCollection - && t_Ref_HashUpdate.validate_skip(cs, weak) // state_update:^(HASH_UPDATE Account) - && RefTo{}.validate_skip(cs, weak); // description:^TransactionDescr + && t_AccountStatus.validate_skip(ops, cs, weak) // orig_status:AccountStatus + && t_AccountStatus.validate_skip(ops, cs, weak) // end_status:AccountStatus + && RefTo{}.validate_skip(ops, cs, weak) // ^[ in_msg:... out_msgs:... ] + && t_CurrencyCollection.validate_skip(ops, cs, weak) // total_fees:CurrencyCollection + && t_Ref_HashUpdate.validate_skip(ops, cs, weak) // state_update:^(HASH_UPDATE Account) + && RefTo{}.validate_skip(ops, cs, weak); // description:^TransactionDescr } bool Transaction::get_storage_fees(Ref cell, td::RefInt256& storage_fees) const { @@ -1573,12 +1599,12 @@ bool AccountBlock::skip(vm::CellSlice& cs) const { && cs.advance_refs(1); // state_update:^(HASH_UPDATE Account) } -bool AccountBlock::validate_skip(vm::CellSlice& cs, bool weak) const { +bool AccountBlock::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { return cs.fetch_ulong(4) == 5 // acc_trans#5 && cs.advance(256) // account_addr:bits256 - && - t_AccountTransactions.validate_skip(cs, weak) // transactions:(HashmapAug 64 ^Transaction CurrencyCollection) - && t_Ref_HashUpdate.validate_skip(cs, weak); // state_update:^(HASH_UPDATE Account) + && t_AccountTransactions.validate_skip(ops, cs, + weak) // transactions:(HashmapAug 64 ^Transaction CurrencyCollection) + && t_Ref_HashUpdate.validate_skip(ops, cs, weak); // state_update:^(HASH_UPDATE Account) } bool AccountBlock::get_total_fees(vm::CellSlice&& cs, block::CurrencyCollection& total_fees) const { @@ -1598,8 +1624,8 @@ const Aug_ShardAccountBlocks aug_ShardAccountBlocks; const HashmapAugE t_ShardAccountBlocks{256, aug_ShardAccountBlocks}; // (HashmapAugE 256 AccountBlock CurrencyCollection) -bool ImportFees::validate_skip(vm::CellSlice& cs, bool weak) const { - return t_Grams.validate_skip(cs, weak) && t_CurrencyCollection.validate_skip(cs, weak); +bool ImportFees::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_Grams.validate_skip(ops, cs, weak) && t_CurrencyCollection.validate_skip(ops, cs, weak); } bool ImportFees::skip(vm::CellSlice& cs) const { @@ -1654,44 +1680,44 @@ bool InMsg::skip(vm::CellSlice& cs) const { return false; } -bool InMsg::validate_skip(vm::CellSlice& cs, bool weak) const { +bool InMsg::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case msg_import_ext: - return cs.advance(3) // msg_import_ext$000 - && t_Ref_Message.validate_skip(cs, weak) // msg:^Message - && t_Ref_Transaction.validate_skip(cs, weak); // transaction:^Transaction + return cs.advance(3) // msg_import_ext$000 + && t_Ref_Message.validate_skip(ops, cs, weak) // msg:^Message + && t_Ref_Transaction.validate_skip(ops, cs, weak); // transaction:^Transaction case msg_import_ihr: - return cs.advance(3) // msg_import_ihr$010 - && t_Ref_Message.validate_skip(cs, weak) // msg:^Message - && t_Ref_Transaction.validate_skip(cs, weak) // transaction:^Transaction - && t_Grams.validate_skip(cs, weak) // ihr_fee:Grams - && t_RefCell.validate_skip(cs, weak); // proof_created:^Cell + return cs.advance(3) // msg_import_ihr$010 + && t_Ref_Message.validate_skip(ops, cs, weak) // msg:^Message + && t_Ref_Transaction.validate_skip(ops, cs, weak) // transaction:^Transaction + && t_Grams.validate_skip(ops, cs, weak) // ihr_fee:Grams + && t_RefCell.validate_skip(ops, cs, weak); // proof_created:^Cell case msg_import_imm: - return cs.advance(3) // msg_import_imm$011 - && t_Ref_MsgEnvelope.validate_skip(cs, weak) // in_msg:^MsgEnvelope - && t_Ref_Transaction.validate_skip(cs, weak) // transaction:^Transaction - && t_Grams.validate_skip(cs, weak); // fwd_fee:Grams + return cs.advance(3) // msg_import_imm$011 + && t_Ref_MsgEnvelope.validate_skip(ops, cs, weak) // in_msg:^MsgEnvelope + && t_Ref_Transaction.validate_skip(ops, cs, weak) // transaction:^Transaction + && t_Grams.validate_skip(ops, cs, weak); // fwd_fee:Grams case msg_import_fin: - return cs.advance(3) // msg_import_fin$100 - && t_Ref_MsgEnvelope.validate_skip(cs, weak) // in_msg:^MsgEnvelope - && t_Ref_Transaction.validate_skip(cs, weak) // transaction:^Transaction - && t_Grams.validate_skip(cs, weak); // fwd_fee:Grams + return cs.advance(3) // msg_import_fin$100 + && t_Ref_MsgEnvelope.validate_skip(ops, cs, weak) // in_msg:^MsgEnvelope + && t_Ref_Transaction.validate_skip(ops, cs, weak) // transaction:^Transaction + && t_Grams.validate_skip(ops, cs, weak); // fwd_fee:Grams case msg_import_tr: - return cs.advance(3) // msg_import_tr$101 - && t_Ref_MsgEnvelope.validate_skip(cs, weak) // in_msg:^MsgEnvelope - && t_Ref_MsgEnvelope.validate_skip(cs, weak) // out_msg:^MsgEnvelope - && t_Grams.validate_skip(cs, weak); // transit_fee:Grams + return cs.advance(3) // msg_import_tr$101 + && t_Ref_MsgEnvelope.validate_skip(ops, cs, weak) // in_msg:^MsgEnvelope + && t_Ref_MsgEnvelope.validate_skip(ops, cs, weak) // out_msg:^MsgEnvelope + && t_Grams.validate_skip(ops, cs, weak); // transit_fee:Grams case msg_discard_fin: - return cs.advance(3) // msg_discard_fin$110 - && t_Ref_MsgEnvelope.validate_skip(cs, weak) // in_msg:^MsgEnvelope - && cs.advance(64) // transaction_id:uint64 - && t_Grams.validate_skip(cs, weak); // fwd_fee:Grams + return cs.advance(3) // msg_discard_fin$110 + && t_Ref_MsgEnvelope.validate_skip(ops, cs, weak) // in_msg:^MsgEnvelope + && cs.advance(64) // transaction_id:uint64 + && t_Grams.validate_skip(ops, cs, weak); // fwd_fee:Grams case msg_discard_tr: - return cs.advance(3) // msg_discard_tr$111 - && t_Ref_MsgEnvelope.validate_skip(cs, weak) // in_msg:^MsgEnvelope - && cs.advance(64) // transaction_id:uint64 - && t_Grams.validate_skip(cs, weak) // fwd_fee:Grams - && t_RefCell.validate_skip(cs, weak); // proof_delivered:^Cell + return cs.advance(3) // msg_discard_tr$111 + && t_Ref_MsgEnvelope.validate_skip(ops, cs, weak) // in_msg:^MsgEnvelope + && cs.advance(64) // transaction_id:uint64 + && t_Grams.validate_skip(ops, cs, weak) // fwd_fee:Grams + && t_RefCell.validate_skip(ops, cs, weak); // proof_delivered:^Cell } return false; } @@ -1829,37 +1855,37 @@ bool OutMsg::skip(vm::CellSlice& cs) const { return false; } -bool OutMsg::validate_skip(vm::CellSlice& cs, bool weak) const { +bool OutMsg::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { switch (get_tag(cs)) { case msg_export_ext: - return cs.advance(3) // msg_export_ext$000 - && t_Ref_Message.validate_skip(cs, weak) // msg:^Message - && t_Ref_Transaction.validate_skip(cs, weak); // transaction:^Transaction + return cs.advance(3) // msg_export_ext$000 + && t_Ref_Message.validate_skip(ops, cs, weak) // msg:^Message + && t_Ref_Transaction.validate_skip(ops, cs, weak); // transaction:^Transaction case msg_export_imm: - return cs.advance(3) // msg_export_imm$010 - && t_Ref_MsgEnvelope.validate_skip(cs, weak) // out_msg:^MsgEnvelope - && t_Ref_Transaction.validate_skip(cs, weak) // transaction:^Transaction - && RefTo{}.validate_skip(cs, weak); // reimport:^InMsg + return cs.advance(3) // msg_export_imm$010 + && t_Ref_MsgEnvelope.validate_skip(ops, cs, weak) // out_msg:^MsgEnvelope + && t_Ref_Transaction.validate_skip(ops, cs, weak) // transaction:^Transaction + && RefTo{}.validate_skip(ops, cs, weak); // reimport:^InMsg case msg_export_new: - return cs.advance(3) // msg_export_new$001 - && t_Ref_MsgEnvelope.validate_skip(cs, weak) // out_msg:^MsgEnvelope - && t_Ref_Transaction.validate_skip(cs, weak); // transaction:^Transaction + return cs.advance(3) // msg_export_new$001 + && t_Ref_MsgEnvelope.validate_skip(ops, cs, weak) // out_msg:^MsgEnvelope + && t_Ref_Transaction.validate_skip(ops, cs, weak); // transaction:^Transaction case msg_export_tr: - return cs.advance(3) // msg_export_tr$011 - && t_Ref_MsgEnvelope.validate_skip(cs, weak) // out_msg:^MsgEnvelope - && RefTo{}.validate_skip(cs, weak); // imported:^InMsg + return cs.advance(3) // msg_export_tr$011 + && t_Ref_MsgEnvelope.validate_skip(ops, cs, weak) // out_msg:^MsgEnvelope + && RefTo{}.validate_skip(ops, cs, weak); // imported:^InMsg case msg_export_deq_imm: - return cs.advance(3) // msg_export_deq_imm$100 - && t_Ref_MsgEnvelope.validate_skip(cs, weak) // out_msg:^MsgEnvelope - && RefTo{}.validate_skip(cs, weak); // reimport:^InMsg + return cs.advance(3) // msg_export_deq_imm$100 + && t_Ref_MsgEnvelope.validate_skip(ops, cs, weak) // out_msg:^MsgEnvelope + && RefTo{}.validate_skip(ops, cs, weak); // reimport:^InMsg case msg_export_deq: - return cs.advance(3) // msg_export_deq$110 - && t_Ref_MsgEnvelope.validate_skip(cs, weak) // out_msg:^MsgEnvelope - && cs.advance(64); // import_block_lt:uint64 + return cs.advance(3) // msg_export_deq$110 + && t_Ref_MsgEnvelope.validate_skip(ops, cs, weak) // out_msg:^MsgEnvelope + && cs.advance(64); // import_block_lt:uint64 case msg_export_tr_req: - return cs.advance(3) // msg_export_tr_req$111 - && t_Ref_MsgEnvelope.validate_skip(cs, weak) // out_msg:^MsgEnvelope - && RefTo{}.validate_skip(cs, weak); // imported:^InMsg + return cs.advance(3) // msg_export_tr_req$111 + && t_Ref_MsgEnvelope.validate_skip(ops, cs, weak) // out_msg:^MsgEnvelope + && RefTo{}.validate_skip(ops, cs, weak); // imported:^InMsg } return false; } @@ -1932,8 +1958,8 @@ const OutMsg t_OutMsg; const Aug_OutMsgDescr aug_OutMsgDescr; const OutMsgDescr t_OutMsgDescr; -bool EnqueuedMsg::validate_skip(vm::CellSlice& cs, bool weak) const { - return cs.advance(64) && t_Ref_MsgEnvelope.validate_skip(cs, weak); +bool EnqueuedMsg::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return cs.advance(64) && t_Ref_MsgEnvelope.validate_skip(ops, cs, weak); } const EnqueuedMsg t_EnqueuedMsg; @@ -1967,9 +1993,9 @@ bool OutMsgQueueInfo::skip(vm::CellSlice& cs) const { return t_OutMsgQueue.skip(cs) && t_ProcessedInfo.skip(cs) && t_IhrPendingInfo.skip(cs); } -bool OutMsgQueueInfo::validate_skip(vm::CellSlice& cs, bool weak) const { - return t_OutMsgQueue.validate_skip(cs, weak) && t_ProcessedInfo.validate_skip(cs, weak) && - t_IhrPendingInfo.validate_skip(cs, weak); +bool OutMsgQueueInfo::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_OutMsgQueue.validate_skip(ops, cs, weak) && t_ProcessedInfo.validate_skip(ops, cs, weak) && + t_IhrPendingInfo.validate_skip(ops, cs, weak); } const OutMsgQueueInfo t_OutMsgQueueInfo; @@ -2005,10 +2031,27 @@ bool ExtBlkRef::unpack(Ref cs_ref, ton::BlockIdExt& blkid, ton::L return true; } +bool ExtBlkRef::store(vm::CellBuilder& cb, const ton::BlockIdExt& blkid, ton::LogicalTime end_lt) const { + return cb.store_long_bool(end_lt, 64) // ext_blk_ref$_ end_lt:uint64 + && cb.store_long_bool(blkid.seqno(), 32) // seq_no:uint32 + && cb.store_bits_bool(blkid.root_hash) // root_hash:bits256 + && cb.store_bits_bool(blkid.file_hash); // file_hash:bits256 = ExtBlkRef; +} + +Ref ExtBlkRef::pack_cell(const ton::BlockIdExt& blkid, ton::LogicalTime end_lt) const { + vm::CellBuilder cb; + return store(cb, blkid, end_lt) ? cb.finalize() : Ref{}; +} + +bool ExtBlkRef::pack_to(Ref& cell, const ton::BlockIdExt& blkid, ton::LogicalTime end_lt) const { + vm::CellBuilder cb; + return store(cb, blkid, end_lt) && cb.finalize_to(cell); +} + const ExtBlkRef t_ExtBlkRef; const BlkMasterInfo t_BlkMasterInfo; -bool ShardIdent::validate_skip(vm::CellSlice& cs, bool weak) const { +bool ShardIdent::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { int shard_pfx_len, workchain_id; unsigned long long shard_pfx; if (cs.fetch_ulong(2) == 0 && cs.fetch_uint_to(6, shard_pfx_len) && cs.fetch_int_to(32, workchain_id) && @@ -2073,8 +2116,8 @@ bool ShardIdent::pack(vm::CellBuilder& cb, ton::ShardIdFull data) const { const ShardIdent t_ShardIdent; -bool BlockIdExt::validate_skip(vm::CellSlice& cs, bool weak) const { - return t_ShardIdent.validate_skip(cs, weak) && cs.advance(32 + 256 * 2); +bool BlockIdExt::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_ShardIdent.validate_skip(ops, cs, weak) && cs.advance(32 + 256 * 2); } bool BlockIdExt::unpack(vm::CellSlice& cs, ton::BlockIdExt& data) const { @@ -2107,21 +2150,21 @@ bool ShardState::skip(vm::CellSlice& cs) const { && Maybe>{}.skip(cs); // custom:(Maybe ^McStateExtra) } -bool ShardState::validate_skip(vm::CellSlice& cs, bool weak) const { +bool ShardState::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { int seq_no; return get_tag(cs) == shard_state && cs.advance(64) // shard_state#9023afe2 blockchain_id:int32 - && t_ShardIdent.validate_skip(cs, weak) // shard_id:ShardIdent + && t_ShardIdent.validate_skip(ops, cs, weak) // shard_id:ShardIdent && cs.fetch_int_to(32, seq_no) // seq_no:int32 && seq_no >= -1 // { seq_no >= -1 } && cs.advance(32 + 32 + 64 + 32) // vert_seq_no:# gen_utime:uint32 gen_lt:uint64 min_ref_mc_seqno:uint32 - && t_Ref_OutMsgQueueInfo.validate_skip(cs, weak) // out_msg_queue_info:^OutMsgQueueInfo - && cs.advance(1) // before_split:Bool - && t_ShardAccounts.validate_skip_ref(cs, weak) // accounts:^ShardAccounts + && t_Ref_OutMsgQueueInfo.validate_skip(ops, cs, weak) // out_msg_queue_info:^OutMsgQueueInfo + && cs.advance(1) // before_split:Bool + && t_ShardAccounts.validate_skip_ref(ops, cs, weak) // accounts:^ShardAccounts && t_ShardState_aux.validate_skip_ref( - cs, + ops, cs, weak) // ^[ total_balance:CurrencyCollection total_validator_fees:CurrencyCollection libraries:(HashmapE 256 LibDescr) master_ref:(Maybe BlkMasterInfo) ] - && Maybe>{}.validate_skip(cs, weak); // custom:(Maybe ^McStateExtra) + && Maybe>{}.validate_skip(ops, cs, weak); // custom:(Maybe ^McStateExtra) } const ShardState t_ShardState; @@ -2134,12 +2177,12 @@ bool ShardState_aux::skip(vm::CellSlice& cs) const { && Maybe{}.skip(cs); // master_ref:(Maybe BlkMasterInfo) } -bool ShardState_aux::validate_skip(vm::CellSlice& cs, bool weak) const { - return cs.advance(128) // overload_history:uint64 underload_history:uint64 - && t_CurrencyCollection.validate_skip(cs, weak) // total_balance:CurrencyCollection - && t_CurrencyCollection.validate_skip(cs, weak) // total_validator_fees:CurrencyCollection - && HashmapE{256, t_LibDescr}.validate_skip(cs, weak) // libraries:(HashmapE 256 LibDescr) - && Maybe{}.validate_skip(cs, weak); // master_ref:(Maybe BlkMasterInfo) +bool ShardState_aux::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return cs.advance(128) // overload_history:uint64 underload_history:uint64 + && t_CurrencyCollection.validate_skip(ops, cs, weak) // total_balance:CurrencyCollection + && t_CurrencyCollection.validate_skip(ops, cs, weak) // total_validator_fees:CurrencyCollection + && HashmapE{256, t_LibDescr}.validate_skip(ops, cs, weak) // libraries:(HashmapE 256 LibDescr) + && Maybe{}.validate_skip(ops, cs, weak); // master_ref:(Maybe BlkMasterInfo) } const ShardState_aux t_ShardState_aux; @@ -2150,10 +2193,10 @@ bool LibDescr::skip(vm::CellSlice& cs) const { && Hashmap{256, t_True}.skip(cs); // publishers:(Hashmap 256 False) } -bool LibDescr::validate_skip(vm::CellSlice& cs, bool weak) const { - return get_tag(cs) == shared_lib_descr && cs.advance(2) // shared_lib_descr$00 - && cs.fetch_ref().not_null() // lib:^Cell - && Hashmap{256, t_True}.validate_skip(cs, weak); // publishers:(Hashmap 256 False) +bool LibDescr::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return get_tag(cs) == shared_lib_descr && cs.advance(2) // shared_lib_descr$00 + && cs.fetch_ref().not_null() // lib:^Cell + && Hashmap{256, t_True}.validate_skip(ops, cs, weak); // publishers:(Hashmap 256 False) } const LibDescr t_LibDescr; @@ -2163,9 +2206,9 @@ bool BlkPrevInfo::skip(vm::CellSlice& cs) const { && (!merged || t_ExtBlkRef.skip(cs)); // prev_alt:merged?ExtBlkRef } -bool BlkPrevInfo::validate_skip(vm::CellSlice& cs, bool weak) const { - return t_ExtBlkRef.validate_skip(cs, weak) // prev_blk_info$_ {merged:#} prev:ExtBlkRef - && (!merged || t_ExtBlkRef.validate_skip(cs, weak)); // prev_alt:merged?ExtBlkRef +bool BlkPrevInfo::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_ExtBlkRef.validate_skip(ops, cs, weak) // prev_blk_info$_ {merged:#} prev:ExtBlkRef + && (!merged || t_ExtBlkRef.validate_skip(ops, cs, weak)); // prev_alt:merged?ExtBlkRef } const BlkPrevInfo t_BlkPrevInfo_0{0}; @@ -2174,8 +2217,8 @@ bool McStateExtra::skip(vm::CellSlice& cs) const { return block::gen::t_McStateExtra.skip(cs); } -bool McStateExtra::validate_skip(vm::CellSlice& cs, bool weak) const { - return block::gen::t_McStateExtra.validate_skip(cs, weak); // ?? +bool McStateExtra::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return block::gen::t_McStateExtra.validate_skip(ops, cs, weak); // ?? } const McStateExtra t_McStateExtra; @@ -2202,8 +2245,8 @@ bool ShardFeeCreated::skip(vm::CellSlice& cs) const { return t_CurrencyCollection.skip(cs) && t_CurrencyCollection.skip(cs); } -bool ShardFeeCreated::validate_skip(vm::CellSlice& cs, bool weak) const { - return t_CurrencyCollection.validate_skip(cs, weak) && t_CurrencyCollection.validate_skip(cs, weak); +bool ShardFeeCreated::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { + return t_CurrencyCollection.validate_skip(ops, cs, weak) && t_CurrencyCollection.validate_skip(ops, cs, weak); } bool ShardFeeCreated::null_value(vm::CellBuilder& cb) const { diff --git a/submodules/ton/tonlib-src/crypto/block/block-parse.h b/submodules/ton/tonlib-src/crypto/block/block-parse.h index acbe9dd426..9590631132 100644 --- a/submodules/ton/tonlib-src/crypto/block/block-parse.h +++ b/submodules/ton/tonlib-src/crypto/block/block-parse.h @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once #include "common/refcnt.hpp" @@ -59,7 +59,7 @@ struct VarUInteger final : TLB_Complex { ln = 32 - td::count_leading_zeroes32(n - 1); } bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; td::RefInt256 as_integer_skip(vm::CellSlice& cs) const override; unsigned long long as_uint(const vm::CellSlice& cs) const override; bool null_value(vm::CellBuilder& cb) const override { @@ -78,7 +78,7 @@ struct VarUIntegerPos final : TLB_Complex { ln = 32 - td::count_leading_zeroes32(n - 1); } bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; td::RefInt256 as_integer_skip(vm::CellSlice& cs) const override; unsigned long long as_uint(const vm::CellSlice& cs) const override; bool store_integer_value(vm::CellBuilder& cb, const td::BigInt256& value) const override; @@ -92,7 +92,7 @@ struct VarInteger final : TLB_Complex { ln = 32 - td::count_leading_zeroes32(n - 1); } bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; td::RefInt256 as_integer_skip(vm::CellSlice& cs) const override; long long as_int(const vm::CellSlice& cs) const override; bool null_value(vm::CellBuilder& cb) const override { @@ -107,7 +107,7 @@ struct VarIntegerNz final : TLB_Complex { ln = 32 - td::count_leading_zeroes32(n - 1); } bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; td::RefInt256 as_integer_skip(vm::CellSlice& cs) const override; long long as_int(const vm::CellSlice& cs) const override; bool store_integer_value(vm::CellBuilder& cb, const td::BigInt256& value) const override; @@ -123,13 +123,13 @@ struct Unary final : TLB { bool skip(vm::CellSlice& cs, int& n) const { return validate_skip(cs, false, n); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override { - return cs.advance(get_size(cs)); + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override { + return skip(cs); } bool skip(vm::CellSlice& cs) const override { - return validate_skip(cs); + return cs.advance(get_size(cs)); } - bool validate(const vm::CellSlice& cs, bool weak = false) const override { + bool validate(int* ops, const vm::CellSlice& cs, bool weak = false) const override { return cs.have(get_size(cs)); } }; @@ -149,7 +149,7 @@ struct HmLabel final : TLB_Complex { int n; return skip(cs, n); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override { + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override { int n; return validate_skip(cs, weak, n); } @@ -162,7 +162,7 @@ struct Hashmap final : TLB_Complex { Hashmap(int _n, const TLB& _val_type) : value_type(_val_type), n(_n) { } bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; }; struct HashmapNode final : TLB_Complex { @@ -173,7 +173,7 @@ struct HashmapNode final : TLB_Complex { } int get_size(const vm::CellSlice& cs) const override; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; int get_tag(const vm::CellSlice& cs) const override { return n > 0 ? hmn_fork : n; } @@ -185,7 +185,7 @@ struct HashmapE final : TLB { HashmapE(int _n, const TLB& _val_type) : root_type(_n, _val_type) { } int get_size(const vm::CellSlice& cs) const override; - bool validate(const vm::CellSlice& cs, bool weak = false) const override; + bool validate(int* ops, const vm::CellSlice& cs, bool weak = false) const override; int get_tag(const vm::CellSlice& cs) const override { return (int)cs.prefetch_ulong(1); } @@ -221,7 +221,7 @@ struct HashmapAug final : TLB_Complex { HashmapAug(int _n, const AugmentationCheckData& _aug) : aug(_aug), n(_n) { } bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool extract_extra(vm::CellSlice& cs) const; }; @@ -232,7 +232,7 @@ struct HashmapAugNode final : TLB_Complex { HashmapAugNode(int _n, const AugmentationCheckData& _aug) : aug(_aug), n(_n) { } bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; int get_tag(const vm::CellSlice& cs) const override { return n > 0 ? ahmn_fork : n; } @@ -244,7 +244,7 @@ struct HashmapAugE final : TLB_Complex { HashmapAugE(int _n, const AugmentationCheckData& _aug) : root_type(_n, std::move(_aug)) { } bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool extract_extra(vm::CellSlice& cs) const; int get_tag(const vm::CellSlice& cs) const override { return (int)cs.prefetch_ulong(1); @@ -252,7 +252,7 @@ struct HashmapAugE final : TLB_Complex { }; struct Grams final : TLB_Complex { - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; td::RefInt256 as_integer_skip(vm::CellSlice& cs) const override; bool null_value(vm::CellBuilder& cb) const override; bool store_integer_value(vm::CellBuilder& cb, const td::BigInt256& value) const override; @@ -264,7 +264,7 @@ extern const Grams t_Grams; struct MsgAddressInt final : TLB_Complex { enum { addr_std = 2, addr_var = 3 }; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; int get_tag(const vm::CellSlice& cs) const override { return (int)cs.prefetch_ulong(2); } @@ -285,6 +285,8 @@ struct MsgAddressInt final : TLB_Complex { bool rewrite = true) const; bool extract_std_address(vm::CellSlice& cs, ton::WorkchainId& workchain, ton::StdSmcAddress& addr, bool rewrite = true) const; + bool store_std_address(vm::CellBuilder& cb, ton::WorkchainId workchain, const ton::StdSmcAddress& addr) const; + Ref pack_std_address(ton::WorkchainId workchain, const ton::StdSmcAddress& addr) const; }; extern const MsgAddressInt t_MsgAddressInt; @@ -301,7 +303,7 @@ extern const MsgAddressExt t_MsgAddressExt; struct MsgAddress final : TLB_Complex { enum { addr_none = 0, addr_ext = 1, addr_std = 2, addr_var = 3 }; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; int get_tag(const vm::CellSlice& cs) const override { return (int)cs.prefetch_ulong(2); } @@ -316,8 +318,8 @@ struct ExtraCurrencyCollection final : TLB { int get_size(const vm::CellSlice& cs) const override { return dict_type.get_size(cs); } - bool validate(const vm::CellSlice& cs, bool weak) const override { - return dict_type.validate(cs, weak); + bool validate(int* ops, const vm::CellSlice& cs, bool weak) const override { + return dict_type.validate(ops, cs, weak); } bool null_value(vm::CellBuilder& cb) const override { return cb.store_zeroes_bool(1); @@ -346,7 +348,7 @@ extern const ExtraCurrencyCollection t_ExtraCurrencyCollection; struct CurrencyCollection final : TLB_Complex { bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; td::RefInt256 as_integer_skip(vm::CellSlice& cs) const override; bool null_value(vm::CellBuilder& cb) const override { return cb.store_bits_same_bool(1 + 4, false); @@ -369,7 +371,7 @@ extern const CurrencyCollection t_CurrencyCollection; struct CommonMsgInfo final : TLB_Complex { enum { int_msg_info = 0, ext_in_msg_info = 2, ext_out_msg_info = 3 }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; int get_tag(const vm::CellSlice& cs) const override { int v = (int)cs.prefetch_ulong(2); return v == 1 ? int_msg_info : v; @@ -400,14 +402,14 @@ struct TickTock final : TLB { extern const TickTock t_TickTock; struct StateInit final : TLB_Complex { - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool get_ticktock(vm::CellSlice& cs, int& ticktock) const; }; extern const StateInit t_StateInit; struct Message final : TLB_Complex { - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool extract_info(vm::CellSlice& cs) const; bool get_created_lt(vm::CellSlice& cs, unsigned long long& created_lt) const; bool is_internal(const vm::CellSlice& cs) const { @@ -423,7 +425,7 @@ struct IntermediateAddress final : TLB_Complex { enum { interm_addr_regular = 0, interm_addr_simple = 2, interm_addr_ext = 3 }; int get_size(const vm::CellSlice& cs) const override; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool fetch_regular(vm::CellSlice& cs, int& use_dst_bits) const { return cs.fetch_uint_to(8, use_dst_bits) && use_dst_bits <= 96; } @@ -437,7 +439,7 @@ extern const IntermediateAddress t_IntermediateAddress; struct MsgEnvelope final : TLB_Complex { bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool extract_fwd_fees_remaining(vm::CellSlice& cs) const; struct Record { typedef MsgEnvelope type_class; @@ -461,28 +463,28 @@ extern const RefTo t_Ref_MsgEnvelope; struct StorageUsed final : TLB_Complex { bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; }; extern const StorageUsed t_StorageUsed; struct StorageUsedShort final : TLB_Complex { bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; }; extern const StorageUsedShort t_StorageUsedShort; struct StorageInfo final : TLB_Complex { bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; }; extern const StorageInfo t_StorageInfo; struct AccountState final : TLB_Complex { enum { account_uninit = 0, account_frozen = 1, account_active = 2 }; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; int get_tag(const vm::CellSlice& cs) const override { int t = (int)cs.prefetch_ulong(2); return t == 3 ? account_active : t; @@ -494,7 +496,7 @@ extern const AccountState t_AccountState; struct AccountStorage final : TLB_Complex { bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool skip_copy_balance(vm::CellBuilder& cb, vm::CellSlice& cs) const; }; @@ -506,7 +508,7 @@ struct Account final : TLB_Complex { Account(bool _allow_empty = false) : allow_empty(_allow_empty) { } bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; // Ref get_balance(const vm::CellSlice& cs) const; bool skip_copy_balance(vm::CellBuilder& cb, vm::CellSlice& cs) const; bool skip_copy_depth_balance(vm::CellBuilder& cb, vm::CellSlice& cs) const; @@ -551,8 +553,8 @@ struct ShardAccount final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return cs.advance_ext(0x140, 1); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override { - return cs.advance(0x140) && t_Ref_Account.validate_skip(cs, weak); + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override { + return cs.advance(0x140) && t_Ref_Account.validate_skip(ops, cs, weak); } static bool unpack(vm::CellSlice& cs, Record& info) { return info.unpack(cs); @@ -567,7 +569,7 @@ extern const ShardAccount t_ShardAccount; struct DepthBalanceInfo final : TLB_Complex { bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool null_value(vm::CellBuilder& cb) const override; bool add_values(vm::CellBuilder& cb, vm::CellSlice& cs1, vm::CellSlice& cs2) const override; }; @@ -588,8 +590,8 @@ struct ShardAccounts final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return dict_type.skip(cs); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override { - return dict_type.validate_skip(cs, weak); + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override { + return dict_type.validate_skip(ops, cs, weak); } }; @@ -613,7 +615,7 @@ extern const AccStatusChange t_AccStatusChange; struct TrStoragePhase final : TLB_Complex { bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool get_storage_fees(vm::CellSlice& cs, td::RefInt256& storage_fees) const; bool maybe_get_storage_fees(vm::CellSlice& cs, td::RefInt256& storage_fees) const; }; @@ -622,14 +624,14 @@ extern const TrStoragePhase t_TrStoragePhase; struct TrCreditPhase final : TLB_Complex { bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; }; extern const TrCreditPhase t_TrCreditPhase; struct TrComputeInternal1 final : TLB_Complex { bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; }; struct ComputeSkipReason final : TLB { @@ -637,7 +639,7 @@ struct ComputeSkipReason final : TLB { int get_size(const vm::CellSlice& cs) const override { return 2; } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override { + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override { return get_tag(cs) >= 0 && cs.advance(2); } int get_tag(const vm::CellSlice& cs) const override { @@ -651,7 +653,7 @@ extern const ComputeSkipReason t_ComputeSkipReason; struct TrComputePhase final : TLB_Complex { enum { tr_phase_compute_skipped = 0, tr_phase_compute_vm = 1 }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; int get_tag(const vm::CellSlice& cs) const override { return (int)cs.prefetch_ulong(1); } @@ -661,7 +663,7 @@ extern const TrComputePhase t_TrComputePhase; struct TrActionPhase final : TLB_Complex { bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; }; extern const TrActionPhase t_TrActionPhase; @@ -669,7 +671,7 @@ extern const TrActionPhase t_TrActionPhase; struct TrBouncePhase final : TLB_Complex { enum { tr_phase_bounce_negfunds = 0, tr_phase_bounce_nofunds = 1, tr_phase_bounce_ok = 2 }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; int get_tag(const vm::CellSlice& cs) const override; }; @@ -677,7 +679,7 @@ extern const TrBouncePhase t_TrBouncePhase; struct SplitMergeInfo final : TLB_Complex { bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; }; extern const SplitMergeInfo t_SplitMergeInfo; @@ -693,7 +695,7 @@ struct TransactionDescr final : TLB_Complex { trans_merge_install = 7 }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; int get_tag(const vm::CellSlice& cs) const override; bool skip_to_storage_phase(vm::CellSlice& cs, bool& found) const; bool get_storage_fees(Ref cell, td::RefInt256& storage_fees) const; @@ -703,14 +705,14 @@ extern const TransactionDescr t_TransactionDescr; struct Transaction_aux final : TLB_Complex { bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; }; extern const Transaction_aux t_Transaction_aux; struct Transaction final : TLB_Complex { bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool get_total_fees(vm::CellSlice&& cs, block::CurrencyCollection& total_fees) const; bool get_descr(Ref cell, Ref& tdescr) const; bool get_descr(vm::CellSlice& cs, Ref& tdescr) const; @@ -733,7 +735,7 @@ struct HashUpdate final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return cs.advance(8 + 256 * 2); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override { + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override { return cs.fetch_ulong(8) == 0x72 && cs.advance(256 * 2); } }; @@ -743,7 +745,7 @@ extern const RefTo t_Ref_HashUpdate; struct AccountBlock final : TLB_Complex { bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool get_total_fees(vm::CellSlice&& cs, block::CurrencyCollection& total_fees) const; }; @@ -760,7 +762,7 @@ extern const HashmapAugE t_ShardAccountBlocks; // (HashmapAugE 256 AccountBlock struct ImportFees final : TLB_Complex { bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool null_value(vm::CellBuilder& cb) const override { return cb.store_bits_same_bool(4 + 4 + 1, false); } @@ -780,7 +782,7 @@ struct InMsg final : TLB_Complex { msg_discard_tr = 7 }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; int get_tag(const vm::CellSlice& cs) const override { return (int)cs.prefetch_ulong(3); } @@ -800,7 +802,7 @@ struct OutMsg final : TLB_Complex { msg_export_tr_req = 7 }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; int get_tag(const vm::CellSlice& cs) const override { return (int)cs.prefetch_ulong(3); } @@ -828,8 +830,8 @@ struct InMsgDescr final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return dict_type.skip(cs); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override { - return dict_type.validate_skip(cs, weak); + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override { + return dict_type.validate_skip(ops, cs, weak); } }; @@ -851,8 +853,8 @@ struct OutMsgDescr final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return dict_type.skip(cs); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override { - return dict_type.validate_skip(cs, weak); + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override { + return dict_type.validate_skip(ops, cs, weak); } }; @@ -865,7 +867,7 @@ struct EnqueuedMsg final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return cs.advance_ext(0x10040); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, EnqueuedMsgDescr& descr) const { return descr.unpack(cs); } @@ -889,8 +891,8 @@ struct OutMsgQueue final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return dict_type.skip(cs); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override { - return dict_type.validate_skip(cs, weak); + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override { + return dict_type.validate_skip(ops, cs, weak); } }; @@ -908,7 +910,7 @@ extern const HashmapE t_IhrPendingInfo; struct OutMsgQueueInfo final : TLB_Complex { bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; }; extern const OutMsgQueueInfo t_OutMsgQueueInfo; @@ -921,6 +923,9 @@ struct ExtBlkRef final : TLB { } bool unpack(vm::CellSlice& cs, ton::BlockIdExt& blkid, ton::LogicalTime* end_lt = nullptr) const; bool unpack(Ref cs_ref, ton::BlockIdExt& blkid, ton::LogicalTime* end_lt = nullptr) const; + bool store(vm::CellBuilder& cb, const ton::BlockIdExt& blkid, ton::LogicalTime end_lt) const; + Ref pack_cell(const ton::BlockIdExt& blkid, ton::LogicalTime end_lt) const; + bool pack_to(Ref& cell, const ton::BlockIdExt& blkid, ton::LogicalTime end_lt) const; }; extern const ExtBlkRef t_ExtBlkRef; @@ -941,7 +946,7 @@ struct ShardIdent final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return cs.advance(get_size(cs)); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; int get_tag(const vm::CellSlice& cs) const override { return 0; } @@ -980,7 +985,7 @@ struct BlockIdExt final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return cs.advance(get_size(cs)); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool unpack(vm::CellSlice& cs, ton::BlockIdExt& data) const; bool pack(vm::CellBuilder& cb, const ton::BlockIdExt& data) const; }; @@ -990,7 +995,7 @@ extern const BlockIdExt t_BlockIdExt; struct ShardState final : TLB_Complex { enum { shard_state = (int)0x9023afe2, split_state = 0x5f327da5 }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; int get_tag(const vm::CellSlice& cs) const override { return (int)cs.prefetch_ulong(32) == shard_state ? shard_state : -1; } @@ -1000,7 +1005,7 @@ extern const ShardState t_ShardState; struct ShardState_aux final : TLB_Complex { bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; int get_tag(const vm::CellSlice& cs) const override { return 0; } @@ -1011,7 +1016,7 @@ extern const ShardState_aux t_ShardState_aux; struct LibDescr final : TLB_Complex { enum { shared_lib_descr = 0 }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; int get_tag(const vm::CellSlice& cs) const override { return (int)cs.prefetch_ulong(2); } @@ -1024,7 +1029,7 @@ struct BlkPrevInfo final : TLB_Complex { BlkPrevInfo(bool _merged) : merged(_merged) { } bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; }; extern const BlkPrevInfo t_BlkPrevInfo_0; @@ -1032,7 +1037,7 @@ extern const BlkPrevInfo t_BlkPrevInfo_0; struct McStateExtra final : TLB_Complex { enum { masterchain_state_extra = 0xcc26 }; bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; }; extern const McStateExtra t_McStateExtra; @@ -1069,7 +1074,7 @@ extern const Aug_OldMcBlocksInfo aug_OldMcBlocksInfo; struct ShardFeeCreated final : TLB_Complex { bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; bool null_value(vm::CellBuilder& cb) const override; bool add_values(vm::CellBuilder& cb, vm::CellSlice& cs1, vm::CellSlice& cs2) const override; }; diff --git a/submodules/ton/tonlib-src/crypto/block/block.cpp b/submodules/ton/tonlib-src/crypto/block/block.cpp index 80723b5856..d9d3c26726 100644 --- a/submodules/ton/tonlib-src/crypto/block/block.cpp +++ b/submodules/ton/tonlib-src/crypto/block/block.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "td/utils/bits.h" #include "block/block.h" @@ -789,10 +789,11 @@ td::Status ShardState::unpack_state(ton::BlockIdExt blkid, Ref prev_st return td::Status::Error(-666, "ShardState of "s + id_.to_str() + " does not contain a valid global_balance"); } if (extra.r1.flags & 1) { - if (extra.r1.block_create_stats->prefetch_ulong(8) != 0x17) { + if (extra.r1.block_create_stats->prefetch_ulong(8) == 0x17) { + block_create_stats_ = std::make_unique(extra.r1.block_create_stats->prefetch_ref(), 256); + } else { return td::Status::Error(-666, "ShardState of "s + id_.to_str() + " does not contain a valid BlockCreateStats"); } - block_create_stats_ = std::make_unique(extra.r1.block_create_stats->prefetch_ref(), 256); } else { block_create_stats_ = std::make_unique(256); } @@ -812,11 +813,11 @@ td::Status ShardState::unpack_out_msg_queue_info(Ref out_msg_queue_inf LOG(DEBUG) << "unpacking ProcessedUpto of our previous block " << id_.to_str(); block::gen::t_ProcessedInfo.print(std::cerr, qinfo.proc_info); } - if (!block::gen::t_ProcessedInfo.validate_csr(qinfo.proc_info)) { + if (!block::gen::t_ProcessedInfo.validate_csr(1024, qinfo.proc_info)) { return td::Status::Error( -666, "ProcessedInfo in the state of "s + id_.to_str() + " is invalid according to automated validity checks"); } - if (!block::gen::t_IhrPendingInfo.validate_csr(qinfo.ihr_pending)) { + if (!block::gen::t_IhrPendingInfo.validate_csr(1024, qinfo.ihr_pending)) { return td::Status::Error( -666, "IhrPendingInfo in the state of "s + id_.to_str() + " is invalid according to automated validity checks"); } @@ -1035,7 +1036,7 @@ td::Status ShardState::split(ton::ShardIdFull subshard) { LOG(DEBUG) << "splitting total_balance"; auto old_total_balance = total_balance_; auto accounts_extra = account_dict_->get_root_extra(); - if (!(accounts_extra.write().advance(5) && total_balance_.validate_unpack(accounts_extra))) { + if (!(accounts_extra.write().advance(5) && total_balance_.validate_unpack(accounts_extra, 1024))) { LOG(ERROR) << "cannot unpack CurrencyCollection from the root of newly-split accounts dictionary"; return td::Status::Error( -666, "error splitting total balance in account dictionary of shardchain state "s + id_.to_str()); @@ -1084,16 +1085,16 @@ int filter_out_msg_queue(vm::AugmentedDictionary& out_queue, ton::ShardIdFull ol }); } -bool CurrencyCollection::validate() const { - return is_valid() && td::sgn(grams) >= 0 && validate_extra(); +bool CurrencyCollection::validate(int max_cells) const { + return is_valid() && td::sgn(grams) >= 0 && validate_extra(max_cells); } -bool CurrencyCollection::validate_extra() const { +bool CurrencyCollection::validate_extra(int max_cells) const { if (extra.is_null()) { return true; } vm::CellBuilder cb; - return cb.store_maybe_ref(extra) && block::tlb::t_ExtraCurrencyCollection.validate_ref(cb.finalize()); + return cb.store_maybe_ref(extra) && block::tlb::t_ExtraCurrencyCollection.validate_ref(max_cells, cb.finalize()); } bool CurrencyCollection::add(const CurrencyCollection& a, const CurrencyCollection& b, CurrencyCollection& c) { @@ -1264,8 +1265,8 @@ bool CurrencyCollection::unpack(Ref csr) { return unpack_CurrencyCollection(std::move(csr), grams, extra) || invalidate(); } -bool CurrencyCollection::validate_unpack(Ref csr) { - return (csr.not_null() && block::tlb::t_CurrencyCollection.validate(*csr) && +bool CurrencyCollection::validate_unpack(Ref csr, int max_cells) { + return (csr.not_null() && block::tlb::t_CurrencyCollection.validate_upto(max_cells, *csr) && unpack_CurrencyCollection(std::move(csr), grams, extra)) || invalidate(); } @@ -1592,7 +1593,7 @@ bool check_one_config_param(Ref cs_ref, td::ConstBitPtr key, td:: } else if (idx < 0) { return true; } - bool ok = block::gen::ConfigParam{idx}.validate_ref(std::move(cell)); + bool ok = block::gen::ConfigParam{idx}.validate_ref(1024, std::move(cell)); if (!ok) { LOG(ERROR) << "configuration parameter #" << idx << " is invalid"; } @@ -1745,7 +1746,7 @@ td::Status unpack_block_prev_blk_ext(Ref block_root, const ton::BlockI block::gen::ExtBlkRef::Record mcref; // _ ExtBlkRef = BlkMasterInfo; ton::ShardIdFull shard; if (!(tlb::unpack_cell(block_root, blk) && tlb::unpack_cell(blk.info, info) && !info.version && - block::tlb::t_ShardIdent.unpack(info.shard.write(), shard) && !info.vert_seq_no && + block::tlb::t_ShardIdent.unpack(info.shard.write(), shard) && (!info.not_master || tlb::unpack_cell(info.master_ref, mcref)))) { return td::Status::Error("cannot unpack block header"); } @@ -1809,6 +1810,9 @@ td::Status unpack_block_prev_blk_ext(Ref block_root, const ton::BlockI } else { mc_blkid = ton::BlockIdExt{ton::masterchainId, ton::shardIdAll, mcref.seq_no, mcref.root_hash, mcref.file_hash}; } + if (shard.is_masterchain() && info.vert_seqno_incr && !info.key_block) { + return td::Status::Error("non-key masterchain block cannot have vert_seqno_incr set"); + } return td::Status::OK(); } @@ -1817,7 +1821,7 @@ td::Status check_block_header(Ref block_root, const ton::BlockIdExt& i block::gen::BlockInfo::Record info; ton::ShardIdFull shard; if (!(tlb::unpack_cell(block_root, blk) && tlb::unpack_cell(blk.info, info) && !info.version && - block::tlb::t_ShardIdent.unpack(info.shard.write(), shard) && !info.vert_seq_no)) { + block::tlb::t_ShardIdent.unpack(info.shard.write(), shard))) { return td::Status::Error("cannot unpack block header"); } ton::BlockId hdr_id{shard, (unsigned)info.seq_no}; @@ -1843,6 +1847,18 @@ td::Status check_block_header(Ref block_root, const ton::BlockIdExt& i return td::Status::OK(); } +std::unique_ptr get_block_create_stats_dict(Ref state_root) { + block::gen::ShardStateUnsplit::Record info; + block::gen::McStateExtra::Record extra; + block::gen::BlockCreateStats::Record_block_create_stats cstats; + if (!(::tlb::unpack_cell(std::move(state_root), info) && info.custom->size_refs() && + ::tlb::unpack_cell(info.custom->prefetch_ref(), extra) && (extra.r1.flags & 1) && + ::tlb::csr_unpack(std::move(extra.r1.block_create_stats), cstats))) { + return {}; + } + return std::make_unique(std::move(cstats.counters), 256); +} + std::unique_ptr get_prev_blocks_dict(Ref state_root) { block::gen::ShardStateUnsplit::Record info; block::gen::McStateExtra::Record extra_info; diff --git a/submodules/ton/tonlib-src/crypto/block/block.h b/submodules/ton/tonlib-src/crypto/block/block.h index fd9a724f26..0d961320bd 100644 --- a/submodules/ton/tonlib-src/crypto/block/block.h +++ b/submodules/ton/tonlib-src/crypto/block/block.h @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once #include "common/refcnt.hpp" @@ -163,12 +163,12 @@ struct MsgProcessedUpto { MsgProcessedUpto(ton::ShardId _shard, ton::BlockSeqno _mcseqno, ton::LogicalTime _lt, td::ConstBitPtr _hash) : shard(_shard), mc_seqno(_mcseqno), last_inmsg_lt(_lt), last_inmsg_hash(_hash) { } - bool operator<(const MsgProcessedUpto& other) const& { + bool operator<(const MsgProcessedUpto& other) const & { return shard < other.shard || (shard == other.shard && mc_seqno < other.mc_seqno); } - bool contains(const MsgProcessedUpto& other) const&; + bool contains(const MsgProcessedUpto& other) const &; bool contains(ton::ShardId other_shard, ton::LogicalTime other_lt, td::ConstBitPtr other_hash, - ton::BlockSeqno other_mc_seqno) const&; + ton::BlockSeqno other_mc_seqno) const &; // NB: this is for checking whether we have already imported an internal message bool already_processed(const EnqueuedMsgDescr& msg) const; }; @@ -323,8 +323,8 @@ struct CurrencyCollection { grams.clear(); return false; } - bool validate() const; - bool validate_extra() const; + bool validate(int max_cells = 1024) const; + bool validate_extra(int max_cells = 1024) const; bool operator==(const CurrencyCollection& other) const; bool operator!=(const CurrencyCollection& other) const { return !operator==(other); @@ -360,7 +360,7 @@ struct CurrencyCollection { bool fetch(vm::CellSlice& cs); bool fetch_exact(vm::CellSlice& cs); bool unpack(Ref csr); - bool validate_unpack(Ref csr); + bool validate_unpack(Ref csr, int max_cells = 1024); Ref pack() const; bool pack_to(Ref& csr) const { return (csr = pack()).not_null(); @@ -514,6 +514,9 @@ struct DiscountedCounter { return last_updated == other.last_updated && total == other.total && cnt2048 <= other.cnt2048 + 1 && other.cnt2048 <= cnt2048 + 1 && cnt65536 <= other.cnt65536 + 1 && other.cnt65536 <= cnt65536 + 1; } + bool modified_since(ton::UnixTime utime) const { + return last_updated >= utime; + } bool validate(); bool increase_by(unsigned count, ton::UnixTime now); bool fetch(vm::CellSlice& cs); @@ -629,6 +632,8 @@ td::Status unpack_block_prev_blk_try(Ref block_root, const ton::BlockI td::Status check_block_header(Ref block_root, const ton::BlockIdExt& id, ton::Bits256* store_shard_hash_to = nullptr); +std::unique_ptr get_block_create_stats_dict(Ref state_root); + std::unique_ptr get_prev_blocks_dict(Ref state_root); bool get_old_mc_block_id(vm::AugmentedDictionary* prev_blocks_dict, ton::BlockSeqno seqno, ton::BlockIdExt& blkid, ton::LogicalTime* end_lt = nullptr); diff --git a/submodules/ton/tonlib-src/crypto/block/block.tlb b/submodules/ton/tonlib-src/crypto/block/block.tlb index ec91ef5755..a30cd89a87 100644 --- a/submodules/ton/tonlib-src/crypto/block/block.tlb +++ b/submodules/ton/tonlib-src/crypto/block/block.tlb @@ -366,6 +366,10 @@ action_send_msg#0ec3c86d mode:(## 8) action_set_code#ad4de08e new_code:^Cell = OutAction; action_reserve_currency#36e6b809 mode:(## 8) currency:CurrencyCollection = OutAction; +libref_hash$0 lib_hash:bits256 = LibRef; +libref_ref$1 library:^Cell = LibRef; +action_change_library#26fa1dd4 mode:(## 7) { mode <= 2 } + libref:LibRef = OutAction; out_list_node$_ prev:^Cell action:OutAction = OutListNode; // @@ -505,6 +509,7 @@ _ (HashmapAugE 32 KeyExtBlkRef KeyMaxLt) = OldMcBlocksInfo; counters#_ last_updated:uint32 total:uint64 cnt2048:uint64 cnt65536:uint64 = Counters; creator_info#4 mc_blocks:Counters shard_blocks:Counters = CreatorStats; block_create_stats#17 counters:(HashmapE 256 CreatorStats) = BlockCreateStats; +block_create_stats_ext#34 counters:(HashmapAugE 256 CreatorStats uint32) = BlockCreateStats; masterchain_state_extra#cc26 shard_hashes:ShardHashes @@ -678,3 +683,77 @@ top_block_descr#d5 proof_for:BlockIdExt signatures:(Maybe ^BlockSignatures) // COLLATED DATA // top_block_descr_set#4ac789f3 collection:(HashmapE 96 ^TopBlockDescr) = TopBlockDescrSet; + +// +// TVM REFLECTION +// +vm_stk_null#00 = VmStackValue; +vm_stk_tinyint#01 value:int64 = VmStackValue; +vm_stk_int#0201_ value:int257 = VmStackValue; +vm_stk_nan#02ff = VmStackValue; +vm_stk_cell#03 cell:^Cell = VmStackValue; +_ cell:^Cell st_bits:(## 10) end_bits:(## 10) { st_bits <= end_bits } + st_ref:(#<= 4) end_ref:(#<= 4) { st_ref <= end_ref } = VmCellSlice; +vm_stk_slice#04 _:VmCellSlice = VmStackValue; +vm_stk_builder#05 cell:^Cell = VmStackValue; +vm_stk_cont#06 cont:VmCont = VmStackValue; +vm_tupref_nil$_ = VmTupleRef 0; +vm_tupref_single$_ entry:^VmStackValue = VmTupleRef 1; +vm_tupref_any$_ {n:#} ref:^(VmTuple (n + 2)) = VmTupleRef (n + 2); +vm_tuple_nil$_ = VmTuple 0; +vm_tuple_tcons$_ {n:#} head:(VmTupleRef n) tail:^VmStackValue = VmTuple (n + 1); +vm_stk_tuple#07 len:(## 16) data:(VmTuple len) = VmStackValue; + +vm_stack#_ depth:(## 24) stack:(VmStackList depth) = VmStack; +vm_stk_cons#_ {n:#} rest:^(VmStackList n) tos:VmStackValue = VmStackList (n + 1); +vm_stk_nil#_ = VmStackList 0; + +_ cregs:(HashmapE 4 VmStackValue) = VmSaveList; +gas_limits#_ remaining:int64 _:^[ max_limit:int64 cur_limit:int64 credit:int64 ] + = VmGasLimits; +_ libraries:(HashmapE 256 ^Cell) = VmLibraries; + +vm_ctl_data$_ nargs:(Maybe uint13) stack:(Maybe VmStack) save:VmSaveList +cp:(Maybe int16) = VmControlData; +vmc_std$00 cdata:VmControlData code:VmCellSlice = VmCont; +vmc_envelope$01 cdata:VmControlData next:^VmCont = VmCont; +vmc_quit$1000 exit_code:int32 = VmCont; +vmc_quit_exc$1001 = VmCont; +vmc_repeat$10100 count:uint63 body:^VmCont after:^VmCont = VmCont; +vmc_until$110000 body:^VmCont after:^VmCont = VmCont; +vmc_again$110001 body:^VmCont = VmCont; +vmc_while_cond$110010 cond:^VmCont body:^VmCont +after:^VmCont = VmCont; +vmc_while_body$110011 cond:^VmCont body:^VmCont +after:^VmCont = VmCont; +vmc_pushint$1111 value:int32 next:^VmCont = VmCont; + +// +// DNS RECORDS +// +_ (HashmapE 16 ^DNSRecord) = DNS_RecordSet; + +chunk_ref$_ {n:#} ref:^(TextChunks (n + 1)) = TextChunkRef (n + 1); +chunk_ref_empty$_ = TextChunkRef 0; +text_chunk$_ {n:#} len:(## 8) data:(bits (len * 8)) next:(TextChunkRef n) = TextChunks (n + 1); +text_chunk_empty$_ = TextChunks 0; +text$_ chunks:(## 8) rest:(TextChunks chunks) = Text; +dns_text#1eda _:Text = DNSRecord; + +dns_next_resolver#ba93 resolver:MsgAddressInt = DNSRecord; // usually in record #-1 + +dns_adnl_address#ad01 adnl_addr:bits256 flags:(## 8) { flags <= 1 } + proto_list:flags . 0?ProtoList = DNSRecord; // often in record #2 +proto_list_nil$0 = ProtoList; +proto_list_next$1 head:Protocol tail:ProtoList = ProtoList; +proto_http#4854 = Protocol; + +dns_smc_address#9fd3 smc_addr:MsgAddressInt flags:(## 8) { flags <= 1 } + cap_list:flags . 0?SmcCapList = DNSRecord; // often in record #1 +cap_list_nil$0 = SmcCapList; +cap_list_next$1 head:SmcCapability tail:SmcCapList = SmcCapList; +cap_method_seqno#5371 = SmcCapability; +cap_method_pubkey#71f4 = SmcCapability; +cap_is_wallet#2177 = SmcCapability; +cap_name#ff name:Text = SmcCapability; + diff --git a/submodules/ton/tonlib-src/crypto/block/check-proof.cpp b/submodules/ton/tonlib-src/crypto/block/check-proof.cpp index 7db7a97c6c..f8d38baac8 100644 --- a/submodules/ton/tonlib-src/crypto/block/check-proof.cpp +++ b/submodules/ton/tonlib-src/crypto/block/check-proof.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "check-proof.h" #include "block/block.h" @@ -219,7 +219,17 @@ td::Status check_account_proof(td::Slice proof, ton::BlockIdExt shard_blk, const } td::Result AccountState::validate(ton::BlockIdExt ref_blk, block::StdAddress addr) const { - TRY_RESULT_PREFIX(root, vm::std_boc_deserialize(state.as_slice(), true), "cannot deserialize account state"); + TRY_RESULT_PREFIX(true_root, vm::std_boc_deserialize(state.as_slice(), true), "cannot deserialize account state"); + Ref root; + + if (is_virtualized && true_root.not_null()) { + root = vm::MerkleProof::virtualize(true_root, 1); + if (root.is_null()) { + return td::Status::Error("account state proof is invalid"); + } + } else { + root = true_root; + } if (blk != ref_blk && ref_blk.id.seqno != ~0U) { return td::Status::Error(PSLICE() << "obtained getAccountState() for a different reference block " << blk.to_str() @@ -241,6 +251,7 @@ td::Result AccountState::validate(ton::BlockIdExt ref_blk, b TRY_STATUS(block::check_account_proof(proof.as_slice(), shard_blk, addr, root, &res.last_trans_lt, &res.last_trans_hash, &res.gen_utime, &res.gen_lt)); res.root = std::move(root); + res.true_root = std::move(true_root); return res; } diff --git a/submodules/ton/tonlib-src/crypto/block/check-proof.h b/submodules/ton/tonlib-src/crypto/block/check-proof.h index 173ae9e475..cfd3a0d2c1 100644 --- a/submodules/ton/tonlib-src/crypto/block/check-proof.h +++ b/submodules/ton/tonlib-src/crypto/block/check-proof.h @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once @@ -44,10 +44,11 @@ struct AccountState { td::BufferSlice shard_proof; td::BufferSlice proof; td::BufferSlice state; + bool is_virtualized{false}; struct Info { - td::Ref root; - ton::LogicalTime last_trans_lt = 0; + td::Ref root, true_root; + ton::LogicalTime last_trans_lt{0}; ton::Bits256 last_trans_hash; ton::LogicalTime gen_lt{0}; td::uint32 gen_utime{0}; diff --git a/submodules/ton/tonlib-src/crypto/block/create-state.cpp b/submodules/ton/tonlib-src/crypto/block/create-state.cpp index 8b92a24fa2..5eb14528c9 100644 --- a/submodules/ton/tonlib-src/crypto/block/create-state.cpp +++ b/submodules/ton/tonlib-src/crypto/block/create-state.cpp @@ -23,7 +23,7 @@ exception statement from your version. If you delete this exception statement from all source files in the program, then also delete it here. - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include #include @@ -633,6 +633,88 @@ void init_words_custom(fift::Dictionary& d) { d.def_stack_word("isWorkchainDescr? ", interpret_is_workchain_descr); } +tlb::TypenameLookup tlb_dict; + +// ( S -- T -1 or 0 ) Looks up TLB type by name +void interpret_tlb_type_lookup(vm::Stack& stack) { + auto ptr = tlb_dict.lookup(stack.pop_string()); + if (ptr) { + stack.push_make_object(ptr); + } + stack.push_bool(ptr); +} + +td::Ref pop_tlb_type(vm::Stack& stack) { + auto res = stack.pop_object(); + if (res.is_null()) { + throw vm::VmError{vm::Excno::type_chk, "not a TLB type"}; + } + return res; +} + +// ( T -- S ) Gets TLB type name +void interpret_tlb_type_name(vm::Stack& stack) { + stack.push_string((*pop_tlb_type(stack))->get_type_name()); +} + +// ( T -- ) Prints TLB type name +void interpret_print_tlb_type(vm::Stack& stack) { + std::cout << (*pop_tlb_type(stack))->get_type_name(); +} + +// ( s T -- ) Dumps (part of) slice s as a value of TLB type T +void interpret_tlb_dump_as(vm::Stack& stack) { + auto tp = pop_tlb_type(stack); + (*tp)->print(std::cout, stack.pop_cellslice()); +} + +// ( s T -- s' S -1 or 0 ) +// Detects prefix of slice s that is a value of TLB type T, returns the remainder as s', and prints the value into String S. +void interpret_tlb_dump_to_str(vm::Stack& stack) { + auto tp = pop_tlb_type(stack); + auto cs = stack.pop_cellslice(); + std::ostringstream os; + bool ok = (*tp)->print_skip(os, cs.write()); + if (ok) { + stack.push(std::move(cs)); + stack.push_string(os.str()); + } + stack.push_bool(ok); +} + +// ( s T -- s' -1 or 0 ) Skips the only prefix of slice s that can be a value of TLB type T +void interpret_tlb_skip(vm::Stack& stack) { + auto tp = pop_tlb_type(stack); + auto cs = stack.pop_cellslice(); + bool ok = (*tp)->skip(cs.write()); + if (ok) { + stack.push(std::move(cs)); + } + stack.push_bool(ok); +} + +// ( s T -- s' -1 or 0 ) Checks whether a prefix of slice s is a valid value of TLB type T, and skips it +void interpret_tlb_validate_skip(vm::Stack& stack) { + auto tp = pop_tlb_type(stack); + auto cs = stack.pop_cellslice(); + bool ok = (*tp)->validate_skip_upto(1048576, cs.write()); + if (ok) { + stack.push(std::move(cs)); + } + stack.push_bool(ok); +} + +void init_words_tlb(fift::Dictionary& d) { + tlb_dict.register_types(block::gen::register_simple_types); + d.def_stack_word("tlb-type-lookup ", interpret_tlb_type_lookup); + d.def_stack_word("tlb-type-name ", interpret_tlb_type_name); + d.def_stack_word("tlb. ", interpret_print_tlb_type); + d.def_stack_word("tlb-dump-as ", interpret_tlb_dump_as); + d.def_stack_word("(tlb-dump-str?) ", interpret_tlb_dump_to_str); + d.def_stack_word("tlb-skip ", interpret_tlb_skip); + d.def_stack_word("tlb-validate-skip ", interpret_tlb_validate_skip); +} + void usage(const char* progname) { std::cerr << "Creates initial state for a TON blockchain, using configuration defined by Fift-language source files\n"; @@ -739,6 +821,7 @@ int main(int argc, char* const argv[]) { fift::init_words_vm(config.dictionary); fift::init_words_ton(config.dictionary); init_words_custom(config.dictionary); + init_words_tlb(config.dictionary); if (script_mode) { fift::import_cmdline_args(config.dictionary, source_list.empty() ? "" : source_list[0], argc - optind, diff --git a/submodules/ton/tonlib-src/crypto/block/dump-block.cpp b/submodules/ton/tonlib-src/crypto/block/dump-block.cpp index ef4e1d8411..716aa3bc51 100644 --- a/submodules/ton/tonlib-src/crypto/block/dump-block.cpp +++ b/submodules/ton/tonlib-src/crypto/block/dump-block.cpp @@ -23,7 +23,7 @@ exception statement from your version. If you delete this exception statement from all source files in the program, then also delete it here. - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "block/block.h" #include "vm/boc.h" @@ -98,7 +98,7 @@ void test1() { block::tlb::ShardIdent::Record shard_id; for (int i = 0; i < 3; i++) { - std::cout << "ShardIdent.validate() = " << block::tlb::t_ShardIdent.validate(csl) << std::endl; + std::cout << "ShardIdent.validate() = " << block::tlb::t_ShardIdent.validate_upto(1024, csl) << std::endl; csl.print_rec(std::cerr); csl.dump(std::cerr, 7); std::cout << "ShardIdent.unpack() = " << block::tlb::t_ShardIdent.unpack(csl, shard_id) << std::endl; @@ -107,9 +107,9 @@ void test1() { << " shard_prefix:" << shard_id.shard_prefix << std::endl; } } - std::cout << "ShardIdent.skip_validate() = " << block::tlb::t_ShardIdent.validate_skip(csl) << std::endl; - std::cout << "ShardIdent.skip_validate() = " << block::tlb::t_ShardIdent.validate_skip(csl) << std::endl; - std::cout << "ShardIdent.skip_validate() = " << block::tlb::t_ShardIdent.validate_skip(csl) << std::endl; + std::cout << "ShardIdent.skip_validate() = " << block::tlb::t_ShardIdent.validate_skip_upto(1024, csl) << std::endl; + std::cout << "ShardIdent.skip_validate() = " << block::tlb::t_ShardIdent.validate_skip_upto(1024, csl) << std::endl; + std::cout << "ShardIdent.skip_validate() = " << block::tlb::t_ShardIdent.validate_skip_upto(1024, csl) << std::endl; using namespace td::literals; std::cout << "Grams.store_intval(239) = " << block::tlb::t_Grams.store_integer_value(cb, "239"_i256) << std::endl; std::cout << "Grams.store_intval(17239) = " << block::tlb::t_Grams.store_integer_value(cb, "17239"_i256) << std::endl; @@ -120,13 +120,13 @@ void test1() { std::cout << "Grams.store_intval(666) = " << block::tlb::t_Grams.store_integer_value(cb, "666"_i256) << std::endl; std::cout << cb << std::endl; cs2 = td::Ref{true, cb.finalize()}; - std::cout << "Grams.validate(cs) = " << block::tlb::t_Grams.validate(*cs) << std::endl; - std::cout << "Grams.validate(cs2) = " << block::tlb::t_Grams.validate(*cs2) << std::endl; + std::cout << "Grams.validate(cs) = " << block::tlb::t_Grams.validate_upto(1024, *cs) << std::endl; + std::cout << "Grams.validate(cs2) = " << block::tlb::t_Grams.validate_upto(1024, *cs2) << std::endl; // block::gen::SplitMergeInfo::Record data; block::gen::Grams::Record data2; - std::cout << "block::gen::Grams.validate(cs) = " << block::gen::t_Grams.validate(*cs) << std::endl; - std::cout << "block::gen::Grams.validate(cs2) = " << block::gen::t_Grams.validate(*cs2) << std::endl; + std::cout << "block::gen::Grams.validate(cs) = " << block::gen::t_Grams.validate_upto(1024, *cs) << std::endl; + std::cout << "block::gen::Grams.validate(cs2) = " << block::gen::t_Grams.validate_upto(1024, *cs2) << std::endl; std::cout << "[cs = " << cs << "]" << std::endl; bool ok = tlb::csr_unpack_inexact(cs, data); std::cout << "block::gen::SplitMergeInfo.unpack(cs, data) = " << ok << std::endl; @@ -182,29 +182,38 @@ void test1() { } void test2(vm::CellSlice& cs) { - std::cout << "Bool.validate() = " << block::tlb::t_Bool.validate(cs) << std::endl; - std::cout << "UInt16.validate() = " << block::tlb::t_uint16.validate(cs) << std::endl; - std::cout << "HashmapE(32,UInt16).validate() = " << block::tlb::HashmapE(32, block::tlb::t_uint16).validate(cs) - << std::endl; + std::cout << "Bool.validate() = " << block::tlb::t_Bool.validate_upto(1024, cs) << std::endl; + std::cout << "UInt16.validate() = " << block::tlb::t_uint16.validate_upto(1024, cs) << std::endl; + std::cout << "HashmapE(32,UInt16).validate() = " + << block::tlb::HashmapE(32, block::tlb::t_uint16).validate_upto(1024, cs) << std::endl; std::cout << "block::gen::HashmapE(32,UInt16).validate() = " - << block::gen::HashmapE{32, block::gen::t_uint16}.validate(cs) << std::endl; + << block::gen::HashmapE{32, block::gen::t_uint16}.validate_upto(1024, cs) << std::endl; } void usage() { - std::cout << "usage: test-block [-S][]\n\tor test-block -h\n\tDumps specified blockchain block or state " - "from , or runs some tests\n\t-S\tDump a blockchain state\n"; + std::cout << "usage: dump-block [-t][-S][]\n\tor dump-block -h\n\tDumps specified blockchain " + "block or state " + "from , or runs some tests\n\t-S\tDump a blockchain state instead of a block\n"; std::exit(2); } int main(int argc, char* const argv[]) { int i; int new_verbosity_level = VERBOSITY_NAME(INFO); - bool dump_state = false; + const char* tname = nullptr; + const tlb::TLB* type = &block::gen::t_Block; auto zerostate = std::make_unique(); - while ((i = getopt(argc, argv, "Shv:")) != -1) { + while ((i = getopt(argc, argv, "CSt:hv:")) != -1) { switch (i) { + case 'C': + type = &block::gen::t_VmCont; + break; case 'S': - dump_state = true; + type = &block::gen::t_ShardStateUnsplit; + break; + case 't': + tname = optarg; + type = nullptr; break; case 'v': new_verbosity_level = VERBOSITY_NAME(FATAL) + (verbosity = td::to_integer(td::Slice(optarg))); @@ -230,12 +239,18 @@ int main(int argc, char* const argv[]) { vm::CellSlice cs{vm::NoVm(), boc}; cs.print_rec(std::cout); std::cout << std::endl; - auto& type = dump_state ? (const tlb::TLB&)block::gen::t_ShardStateUnsplit : block::gen::t_Block; - std::string type_name = dump_state ? "ShardState" : "Block"; - type.print_ref(std::cout, boc); + if (!type) { + tlb::TypenameLookup dict(block::gen::register_simple_types); + type = dict.lookup(tname); + if (!type) { + std::cerr << "unknown TL-B type " << tname << std::endl; + std::exit(3); + } + } + type->print_ref(std::cout, boc); std::cout << std::endl; - bool ok = type.validate_ref(boc); - std::cout << "(" << (ok ? "" : "in") << "valid " << type_name << ")" << std::endl; + bool ok = type->validate_ref(1048576, boc); + std::cout << "(" << (ok ? "" : "in") << "valid " << *type << ")" << std::endl; } } if (!done) { diff --git a/submodules/ton/tonlib-src/crypto/block/mc-config.cpp b/submodules/ton/tonlib-src/crypto/block/mc-config.cpp index b5959f7557..555b26033e 100644 --- a/submodules/ton/tonlib-src/crypto/block/mc-config.cpp +++ b/submodules/ton/tonlib-src/crypto/block/mc-config.cpp @@ -23,7 +23,7 @@ exception statement from your version. If you delete this exception statement from all source files in the program, then also delete it here. - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "mc-config.h" #include "block/block.h" @@ -567,6 +567,21 @@ td::Result Config::do_get_gas_limits_prices(td::Ref c } return res; } + +td::Result Config::get_dns_root_addr() const { + auto cell = get_config_param(4); + if (cell.is_null()) { + return td::Status::Error(PSLICE() << "configuration parameter " << 4 << " with dns root address is absent"); + } + auto cs = vm::load_cell_slice(std::move(cell)); + if (cs.size() != 0x100) { + return td::Status::Error(PSLICE() << "configuration parameter " << 4 << " with dns root address has wrong size"); + } + ton::StdSmcAddress res; + CHECK(cs.fetch_bits_to(res)); + return res; +} + td::Result Config::get_gas_limits_prices(bool is_masterchain) const { auto id = is_masterchain ? 20 : 21; auto cell = get_config_param(id); @@ -752,8 +767,8 @@ Ref McShardDescr::from_block(Ref block_root, Ref::max(); int len = id.pfx_len(); while (true) { - cs.load(vm::NoVmOrd{}, leaf ? root : std::move(root)); + cs.load(vm::NoVmOrd(), leaf ? root : std::move(root)); int t = (int)cs.fetch_ulong(1); if (t < 0) { return false; // throw DictError ? @@ -1108,7 +1123,7 @@ std::vector ShardConfig::get_shard_hash_ids( std::stack, unsigned long long>> stack; stack.emplace(cs_ref->prefetch_ref(), ton::shardIdAll); while (!stack.empty()) { - vm::CellSlice cs{vm::NoVm{}, std::move(stack.top().first)}; + vm::CellSlice cs{vm::NoVmOrd(), std::move(stack.top().first)}; unsigned long long shard = stack.top().second; stack.pop(); int t = (int)cs.fetch_ulong(1); @@ -1224,7 +1239,7 @@ bool ShardConfig::new_workchain(ton::WorkchainId workchain, ton::BlockSeqno reg_ cb.store_zeroes_bool( 1 + 5 + 5) // split_merge_at:FutureSplitMerge fees_collected:CurrencyCollection funds_created:CurrencyCollection - && cb.finalize_to(cell) && block::gen::t_BinTree_ShardDescr.validate_ref(cell) && + && cb.finalize_to(cell) && block::gen::t_BinTree_ShardDescr.validate_ref(1024, cell) && shard_hashes_dict_->set_ref(td::BitArray<32>{workchain}, std::move(cell), vm::Dictionary::SetMode::Add); } @@ -1454,7 +1469,7 @@ static bool btree_set(Ref& root, ton::ShardId shard, Ref val } bool ShardConfig::set_shard_info(ton::ShardIdFull shard, Ref value) { - if (!gen::t_BinTree_ShardDescr.validate_ref(value)) { + if (!gen::t_BinTree_ShardDescr.validate_ref(1024, value)) { LOG(ERROR) << "attempting to store an invalid (BinTree ShardDescr) at shard configuration position " << shard.to_str(); gen::t_BinTree_ShardDescr.print_ref(std::cerr, value); @@ -1710,6 +1725,30 @@ std::vector Config::compute_total_validator_set(int next) c return res.move_as_ok()->export_validator_set(); } +td::Result> Config::unpack_validator_set_start_stop(Ref vset_root) { + if (vset_root.is_null()) { + return td::Status::Error("validator set absent"); + } + gen::ValidatorSet::Record_validators_ext rec; + if (tlb::unpack_cell(vset_root, rec)) { + return std::pair(rec.utime_since, rec.utime_until); + } + gen::ValidatorSet::Record_validators rec0; + if (tlb::unpack_cell(std::move(vset_root), rec0)) { + return std::pair(rec0.utime_since, rec0.utime_until); + } + return td::Status::Error("validator set is invalid"); +} + +std::pair Config::get_validator_set_start_stop(int next) const { + auto res = unpack_validator_set_start_stop(get_config_param(next < 0 ? 32 : (next ? 36 : 34))); + if (res.is_error()) { + return {0, 0}; + } else { + return res.move_as_ok(); + } +} + bool WorkchainInfo::unpack(ton::WorkchainId wc, vm::CellSlice& cs) { workchain = ton::workchainInvalid; if (wc == ton::workchainInvalid) { diff --git a/submodules/ton/tonlib-src/crypto/block/mc-config.h b/submodules/ton/tonlib-src/crypto/block/mc-config.h index 241ae88c55..8541110ffe 100644 --- a/submodules/ton/tonlib-src/crypto/block/mc-config.h +++ b/submodules/ton/tonlib-src/crypto/block/mc-config.h @@ -14,7 +14,7 @@ You should have received a copy of the GNU General Public License along with TON Blockchain. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once #include "common/refcnt.hpp" @@ -50,7 +50,7 @@ struct ValidatorDescr { : pubkey(_pubkey), weight(_weight), cum_weight(_cum_weight) { adnl_addr.set_zero(); } - bool operator<(td::uint64 wt_pos) const& { + bool operator<(td::uint64 wt_pos) const & { return cum_weight < wt_pos; } }; @@ -534,6 +534,7 @@ class Config { bool create_stats_enabled() const { return has_capability(ton::capCreateStatsEnabled); } + td::Result get_dns_root_addr() const; bool set_block_id_ext(const ton::BlockIdExt& block_id_ext); td::Result> get_special_smartcontracts(bool without_config = false) const; bool is_special_smartcontract(const ton::StdSmcAddress& addr) const; @@ -558,6 +559,7 @@ class Config { const ValidatorSet* get_cur_validator_set() const { return cur_validators_.get(); } + std::pair get_validator_set_start_stop(int next = 0) const; ton::ValidatorSessionConfig get_consensus_config() const; bool foreach_config_param(std::function)> scan_func) const; Ref get_workchain_info(ton::WorkchainId workchain_id) const; @@ -577,6 +579,7 @@ class Config { static td::Result> unpack_config(Ref config_csr, int mode = 0); static td::Result> extract_from_state(Ref mc_state_root, int mode = 0); static td::Result> extract_from_key_block(Ref key_block_root, int mode = 0); + static td::Result> unpack_validator_set_start_stop(Ref root); protected: Config(int _mode) : mode(_mode) { diff --git a/submodules/ton/tonlib-src/crypto/block/transaction.cpp b/submodules/ton/tonlib-src/crypto/block/transaction.cpp index 6667cf8774..34abfff13d 100644 --- a/submodules/ton/tonlib-src/crypto/block/transaction.cpp +++ b/submodules/ton/tonlib-src/crypto/block/transaction.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "block/transaction.h" #include "block/block.h" @@ -23,7 +23,7 @@ #include "td/utils/bits.h" #include "td/utils/uint128.h" #include "ton/ton-shard.h" -#include "vm/continuation.h" +#include "vm/vm.h" namespace block { using td::Ref; @@ -150,7 +150,7 @@ bool Account::unpack_storage_info(vm::CellSlice& cs) { return false; } } else { - due_payment = td::RefInt256{true, 0}; + due_payment = td::zero_refint(); } unsigned long long u = 0; u |= storage_stat.cells = block::tlb::t_VarUInteger_7.as_uint(*used.cells); @@ -369,7 +369,7 @@ bool Account::init_new(ton::UnixTime now) { now_ = now; last_paid = 0; storage_stat.clear(); - due_payment = td::RefInt256{true, 0}; + due_payment = td::zero_refint(); balance.set_zero(); if (my_addr_exact.is_null()) { vm::CellBuilder cb; @@ -463,6 +463,7 @@ Transaction::Transaction(const Account& _account, int ttype, ton::LogicalTime re , my_addr(_account.my_addr) , my_addr_exact(_account.my_addr_exact) , balance(_account.balance) + , original_balance(_account.balance) , due_payment(_account.due_payment) , last_paid(_account.last_paid) , new_code(_account.code) @@ -472,6 +473,9 @@ Transaction::Transaction(const Account& _account, int ttype, ton::LogicalTime re start_lt = std::max(req_start_lt, account.last_trans_end_lt_); end_lt = start_lt + 1; acc_status = (account.status == Account::acc_nonexist ? Account::acc_uninit : account.status); + if (acc_status == Account::acc_frozen) { + frozen_hash = account.state_hash; + } } bool Transaction::unpack_input_msg(bool ihr_delivered, const ActionPhaseConfig* cfg) { @@ -503,7 +507,7 @@ bool Transaction::unpack_input_msg(bool ihr_delivered, const ActionPhaseConfig* if (ihr_delivered) { in_fwd_fee = std::move(ihr_fee); } else { - in_fwd_fee = td::RefInt256{true, 0}; + in_fwd_fee = td::zero_refint(); msg_balance_remaining += std::move(ihr_fee); } if (info.created_lt >= start_lt) { @@ -543,7 +547,7 @@ bool Transaction::unpack_input_msg(bool ihr_delivered, const ActionPhaseConfig* LOG(DEBUG) << "computed fwd fees set to zero for special account"; fees_c.first = fees_c.second = 0; } - in_fwd_fee = td::RefInt256{true, fees_c.first}; + in_fwd_fee = td::make_refint(fees_c.first); if (balance.grams < in_fwd_fee) { LOG(DEBUG) << "cannot pay for importing this external message"; return false; @@ -615,19 +619,19 @@ bool Transaction::prepare_storage_phase(const StoragePhaseConfig& cfg, bool forc res->is_special = account.is_special; last_paid = res->last_paid_updated = (res->is_special ? 0 : now); if (to_pay.is_null() || sgn(to_pay) == 0) { - res->fees_collected = res->fees_due = td::RefInt256{true, 0}; + res->fees_collected = res->fees_due = td::zero_refint(); } else if (to_pay <= balance.grams) { res->fees_collected = to_pay; - res->fees_due = td::RefInt256{true, 0}; + res->fees_due = td::zero_refint(); balance -= std::move(to_pay); } else if (acc_status == Account::acc_frozen && !force_collect && to_pay + due_payment < cfg.delete_due_limit) { // do not collect fee res->last_paid_updated = (res->is_special ? 0 : account.last_paid); - res->fees_collected = res->fees_due = td::RefInt256{true, 0}; + res->fees_collected = res->fees_due = td::zero_refint(); } else { res->fees_collected = balance.grams; res->fees_due = std::move(to_pay) - std::move(balance.grams); - balance.grams = td::RefInt256{true, 0}; + balance.grams = td::zero_refint(); if (!res->is_special) { auto total_due = res->fees_due + due_payment; switch (acc_status) { @@ -691,19 +695,23 @@ bool ComputePhaseConfig::parse_GasLimitsPrices(Ref cs, td::RefInt } block::gen::GasLimitsPrices::Record_gas_flat_pfx flat; if (tlb::csr_unpack(cs, flat)) { - bool ok = parse_GasLimitsPrices(std::move(flat.other), freeze_due_limit, delete_due_limit); - flat_gas_limit = flat.flat_gas_limit; - flat_gas_price = flat.flat_gas_price; - return ok; + return parse_GasLimitsPrices_internal(std::move(flat.other), freeze_due_limit, delete_due_limit, + flat.flat_gas_limit, flat.flat_gas_price); + } else { + return parse_GasLimitsPrices_internal(std::move(cs), freeze_due_limit, delete_due_limit); } - flat_gas_limit = flat_gas_price = 0; +} + +bool ComputePhaseConfig::parse_GasLimitsPrices_internal(Ref cs, td::RefInt256& freeze_due_limit, + td::RefInt256& delete_due_limit, td::uint64 _flat_gas_limit, + td::uint64 _flat_gas_price) { auto f = [&](const auto& r, td::uint64 spec_limit) { gas_limit = r.gas_limit; special_gas_limit = spec_limit; gas_credit = r.gas_credit; gas_price = r.gas_price; - freeze_due_limit = td::RefInt256{true, r.freeze_due_limit}; - delete_due_limit = td::RefInt256{true, r.delete_due_limit}; + freeze_due_limit = td::make_refint(r.freeze_due_limit); + delete_due_limit = td::make_refint(r.delete_due_limit); }; block::gen::GasLimitsPrices::Record_gas_prices_ext rec; if (tlb::csr_unpack(cs, rec)) { @@ -716,15 +724,17 @@ bool ComputePhaseConfig::parse_GasLimitsPrices(Ref cs, td::RefInt return false; } } + flat_gas_limit = _flat_gas_limit; + flat_gas_price = _flat_gas_price; compute_threshold(); return true; } void ComputePhaseConfig::compute_threshold() { - gas_price256 = td::RefInt256{true, gas_price}; + gas_price256 = td::make_refint(gas_price); if (gas_limit > flat_gas_limit) { max_gas_threshold = - td::rshift(gas_price256 * (gas_limit - flat_gas_limit), 16, 1) + td::make_refint(flat_gas_price); + td::rshift(gas_price256 * (gas_limit - flat_gas_limit), 16, 1) + td::make_bigint(flat_gas_price); } else { max_gas_threshold = td::make_refint(flat_gas_price); } @@ -821,8 +831,8 @@ Ref Transaction::prepare_vm_c7(const ComputePhaseConfig& cfg) const { } auto tuple = vm::make_tuple_ref( td::make_refint(0x076ef1ea), // [ magic:0x076ef1ea - td::make_refint(0), // actions:Integer - td::make_refint(0), // msgs_sent:Integer + td::zero_refint(), // actions:Integer + td::zero_refint(), // msgs_sent:Integer td::make_refint(now), // unixtime:Integer td::make_refint(account.block_lt), // block_lt:Integer td::make_refint(start_lt), // trans_lt:Integer @@ -906,6 +916,7 @@ bool Transaction::prepare_compute_phase(const ComputePhaseConfig& cfg) { // ... compute_phase = std::make_unique(); ComputePhase& cp = *(compute_phase.get()); + original_balance -= total_fees; if (td::sgn(balance.grams) <= 0) { // no gas cp.skip_reason = ComputePhase::sk_no_gas; @@ -1004,16 +1015,15 @@ bool Transaction::prepare_compute_phase(const ComputePhaseConfig& cfg) { } if (cp.accepted) { if (account.is_special) { - cp.gas_fees = td::RefInt256{true, 0}; + cp.gas_fees = td::zero_refint(); } else { cp.gas_fees = cfg.compute_gas_price(cp.gas_used); total_fees += cp.gas_fees; balance -= cp.gas_fees; } - if (verbosity > 2) { - std::cerr << "gas fees: " << cp.gas_fees << " = " << cfg.gas_price256 << " * " << cp.gas_used - << " /2^16 ; price=" << cfg.gas_price << "; remaining balance=" << balance << std::endl; - } + LOG(DEBUG) << "gas fees: " << cp.gas_fees->to_dec_string() << " = " << cfg.gas_price256->to_dec_string() << " * " + << cp.gas_used << " /2^16 ; price=" << cfg.gas_price << "; flat rate=[" << cfg.flat_gas_price << " for " + << cfg.flat_gas_limit << "]; remaining balance=" << balance.to_str(); CHECK(td::sgn(balance.grams) >= 0); } return true; @@ -1033,8 +1043,8 @@ bool Transaction::prepare_action_phase(const ActionPhaseConfig& cfg) { ap.action_list_hash = list->get_hash().bits(); ap.remaining_balance = balance; ap.end_lt = end_lt; - ap.total_fwd_fees = td::RefInt256{true, 0}; - ap.total_action_fees = td::RefInt256{true, 0}; + ap.total_fwd_fees = td::zero_refint(); + ap.total_action_fees = td::zero_refint(); ap.reserved_balance.set_zero(); int n = 0; @@ -1098,6 +1108,9 @@ bool Transaction::prepare_action_phase(const ActionPhaseConfig& cfg) { case block::gen::OutAction::action_reserve_currency: err_code = try_action_reserve_currency(cs, ap, cfg); break; + case block::gen::OutAction::action_change_library: + err_code = try_action_change_library(cs, ap, cfg); + break; } if (err_code) { ap.result_code = (err_code == -1 ? 34 : err_code); @@ -1148,6 +1161,56 @@ int Transaction::try_action_set_code(vm::CellSlice& cs, ActionPhase& ap, const A return 0; } +int Transaction::try_action_change_library(vm::CellSlice& cs, ActionPhase& ap, const ActionPhaseConfig& cfg) { + block::gen::OutAction::Record_action_change_library rec; + if (!tlb::unpack_exact(cs, rec)) { + return -1; + } + // mode: +0 = remove library, +1 = add private library, +2 = add public library + Ref lib_ref = rec.libref->prefetch_ref(); + ton::Bits256 hash; + if (lib_ref.not_null()) { + hash = lib_ref->get_hash().bits(); + } else { + CHECK(rec.libref.write().fetch_ulong(1) == 0 && rec.libref.write().fetch_bits_to(hash)); + } + try { + vm::Dictionary dict{new_library, 256}; + if (!rec.mode) { + // remove library + dict.lookup_delete(hash); + LOG(DEBUG) << "removed " << ((rec.mode >> 1) ? "public" : "private") << " library with hash " << hash.to_hex(); + } else { + auto val = dict.lookup(hash); + if (val.not_null()) { + bool is_public = val->prefetch_ulong(1); + auto ref = val->prefetch_ref(); + if (hash == ref->get_hash().bits()) { + lib_ref = ref; + if (is_public == (rec.mode >> 1)) { + // library already in required state + ap.spec_actions++; + return 0; + } + } + } + if (lib_ref.is_null()) { + // library code not found + return 41; + } + vm::CellBuilder cb; + CHECK(cb.store_bool_bool(rec.mode >> 1) && cb.store_ref_bool(std::move(lib_ref))); + CHECK(dict.set_builder(hash, cb)); + LOG(DEBUG) << "added " << ((rec.mode >> 1) ? "public" : "private") << " library with hash " << hash.to_hex(); + } + new_library = std::move(dict).extract_root_cell(); + } catch (vm::VmError& vme) { + return 42; + } + ap.spec_actions++; + return 0; +} + // msg_fwd_fees = (lump_price + ceil((bit_price * msg.bits + cell_price * msg.cells)/2^16)) nanograms // ihr_fwd_fees = ceil((msg_fwd_fees * ihr_price_factor)/2^16) nanograms // bits in the root cell of a message are not included in msg.bits (lump_price pays for them) @@ -1369,7 +1432,7 @@ int Transaction::try_action_send_msg(const vm::CellSlice& cs0, ActionPhase& ap, info.ihr_disabled = true; info.bounce = false; info.bounced = false; - fwd_fee = ihr_fee = td::RefInt256{true, 0}; + fwd_fee = ihr_fee = td::zero_refint(); } else { // int_msg_info$0 constructor if (!tlb::csr_unpack(msg.info, info) || !block::tlb::t_CurrencyCollection.validate_csr(info.value)) { @@ -1422,10 +1485,10 @@ int Transaction::try_action_send_msg(const vm::CellSlice& cs0, ActionPhase& ap, // set fees to computed values if (fwd_fee->unsigned_fits_bits(63) && fwd_fee->to_long() < (long long)fees_c.first) { - fwd_fee = td::RefInt256{true, fees_c.first}; + fwd_fee = td::make_refint(fees_c.first); } if (fees_c.second && ihr_fee->unsigned_fits_bits(63) && ihr_fee->to_long() < (long long)fees_c.second) { - ihr_fee = td::RefInt256{true, fees_c.second}; + ihr_fee = td::make_refint(fees_c.second); } Ref new_msg; @@ -1442,7 +1505,7 @@ int Transaction::try_action_send_msg(const vm::CellSlice& cs0, ActionPhase& ap, } if (info.ihr_disabled) { // if IHR is disabled, IHR fees will be always zero - ihr_fee = td::RefInt256{true, 0}; + ihr_fee = td::zero_refint(); } // extract value to be carried by the message block::CurrencyCollection req; @@ -1592,7 +1655,7 @@ int Transaction::try_action_send_msg(const vm::CellSlice& cs0, ActionPhase& ap, int Transaction::try_action_reserve_currency(vm::CellSlice& cs, ActionPhase& ap, const ActionPhaseConfig& cfg) { block::gen::OutAction::Record_action_reserve_currency rec; - if (!tlb::unpack_exact(cs, rec) || (rec.mode & ~3)) { + if (!tlb::unpack_exact(cs, rec) || (rec.mode & ~15)) { return -1; } int mode = rec.mode; @@ -1603,7 +1666,21 @@ int Transaction::try_action_reserve_currency(vm::CellSlice& cs, ActionPhase& ap, return -1; } LOG(DEBUG) << "action_reserve_currency: mode=" << mode << ", reserve=" << reserve.to_str() - << ", balance=" << ap.remaining_balance.to_str(); + << ", balance=" << ap.remaining_balance.to_str() << ", original balance=" << original_balance.to_str(); + if (mode & 4) { + if (mode & 8) { + reserve = original_balance - reserve; + } else { + reserve += original_balance; + } + } else if (mode & 8) { + LOG(DEBUG) << "invalid reserve mode " << mode; + return -1; + } + if (!reserve.is_valid() || td::sgn(reserve.grams) < 0) { + LOG(DEBUG) << "cannot reserve a negative amount: " << reserve.to_str(); + return -1; + } if (reserve.grams > ap.remaining_balance.grams) { if (mode & 2) { reserve.grams = ap.remaining_balance.grams; @@ -1683,10 +1760,10 @@ bool Transaction::prepare_bounce_phase(const ActionPhaseConfig& cfg) { balance -= msg_balance; CHECK(balance.is_valid()); // debit total forwarding fees from the message's balance, then split forwarding fees into our part and remaining part - msg_balance -= td::RefInt256{true, bp.fwd_fees}; + msg_balance -= td::make_refint(bp.fwd_fees); bp.fwd_fees_collected = msg_prices.get_first_part(bp.fwd_fees); bp.fwd_fees -= bp.fwd_fees_collected; - total_fees += td::RefInt256{true, bp.fwd_fees_collected}; + total_fees += td::make_refint(bp.fwd_fees_collected); // serialize outbound message info.created_lt = end_lt++; info.created_at = now; @@ -1771,7 +1848,7 @@ bool Transaction::compute_state() { // code:(Maybe ^Cell) data:(Maybe ^Cell) library:(HashmapE 256 SimpleLib) auto frozen_state = cb2.finalize(); frozen_hash = frozen_state->get_hash().bits(); - if (verbosity >= 3 * 0) { // !!!DEBUG!!! + if (verbosity >= 3 * 1) { // !!!DEBUG!!! std::cerr << "freezing state of smart contract: "; block::gen::t_StateInit.print_ref(std::cerr, frozen_state); CHECK(block::gen::t_StateInit.validate_ref(frozen_state)); diff --git a/submodules/ton/tonlib-src/crypto/block/transaction.h b/submodules/ton/tonlib-src/crypto/block/transaction.h index 25f8059560..5ab34710d0 100644 --- a/submodules/ton/tonlib-src/crypto/block/transaction.h +++ b/submodules/ton/tonlib-src/crypto/block/transaction.h @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once #include "common/refcnt.hpp" @@ -65,10 +65,10 @@ struct NewOutMsg { NewOutMsg(ton::LogicalTime _lt, Ref _msg, Ref _trans) : lt(_lt), msg(std::move(_msg)), trans(std::move(_trans)) { } - bool operator<(const NewOutMsg& other) const& { + bool operator<(const NewOutMsg& other) const & { return lt < other.lt || (lt == other.lt && msg->get_hash() < other.msg->get_hash()); } - bool operator>(const NewOutMsg& other) const& { + bool operator>(const NewOutMsg& other) const & { return lt > other.lt || (lt == other.lt && other.msg->get_hash() < msg->get_hash()); } }; @@ -130,6 +130,11 @@ struct ComputePhaseConfig { } bool parse_GasLimitsPrices(Ref cs, td::RefInt256& freeze_due_limit, td::RefInt256& delete_due_limit); bool parse_GasLimitsPrices(Ref cell, td::RefInt256& freeze_due_limit, td::RefInt256& delete_due_limit); + + private: + bool parse_GasLimitsPrices_internal(Ref cs, td::RefInt256& freeze_due_limit, + td::RefInt256& delete_due_limit, td::uint64 flat_gas_limit = 0, + td::uint64 flat_gas_price = 0); }; struct ActionPhaseConfig { @@ -189,10 +194,6 @@ struct ActionPhase { Ref new_code; td::BitArray<256> action_list_hash; block::CurrencyCollection remaining_balance, reserved_balance; - // td::RefInt256 remaining_balance; - // Ref remaining_extra; - // td::RefInt256 reserved_balance; - // Ref reserved_extra; std::vector> action_list; // processed in reverse order std::vector> out_msgs; ton::LogicalTime end_lt; @@ -314,7 +315,7 @@ struct Transaction { const Account& account; // only `commit` method modifies the account Ref my_addr, my_addr_exact; // almost the same as in account.* ton::LogicalTime start_lt, end_lt; - block::CurrencyCollection balance; + block::CurrencyCollection balance, original_balance; block::CurrencyCollection msg_balance_remaining; td::RefInt256 due_payment; td::RefInt256 in_fwd_fee, msg_fwd_fees; @@ -371,6 +372,7 @@ struct Transaction { Ref prepare_vm_c7(const ComputePhaseConfig& cfg) const; bool prepare_rand_seed(td::BitArray<256>& rand_seed, const ComputePhaseConfig& cfg) const; int try_action_set_code(vm::CellSlice& cs, ActionPhase& ap, const ActionPhaseConfig& cfg); + int try_action_change_library(vm::CellSlice& cs, ActionPhase& ap, const ActionPhaseConfig& cfg); int try_action_send_msg(const vm::CellSlice& cs, ActionPhase& ap, const ActionPhaseConfig& cfg, int redoing = 0); int try_action_reserve_currency(vm::CellSlice& cs, ActionPhase& ap, const ActionPhaseConfig& cfg); bool check_replace_src_addr(Ref& src_addr) const; diff --git a/submodules/ton/tonlib-src/crypto/common/bigint.hpp b/submodules/ton/tonlib-src/crypto/common/bigint.hpp index 6734f07e32..7f6cf971e3 100644 --- a/submodules/ton/tonlib-src/crypto/common/bigint.hpp +++ b/submodules/ton/tonlib-src/crypto/common/bigint.hpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once #include @@ -169,6 +169,8 @@ class PropagateConstSpan { size_t size_{0}; }; +struct Normalize {}; + template class AnyIntView { public: @@ -308,6 +310,10 @@ class BigIntG { explicit BigIntG(word_t x) : n(1) { digits[0] = x; } + BigIntG(Normalize, word_t x) : n(1) { + digits[0] = x; + normalize_bool(); + } BigIntG(const BigIntG& x) : n(x.n) { std::memcpy(digits, x.digits, n * sizeof(word_t)); ///std::cout << "(BiCC " << (const void*)&x << "->" << (void*)this << ")"; @@ -2515,6 +2521,11 @@ extern template class AnyIntView; extern template class BigIntG<257, BigIntInfo>; typedef BigIntG<257, BigIntInfo> BigInt256; +template +BigIntG make_bigint(long long x) { + return BigIntG{Normalize(), x}; +} + namespace literals { extern BigInt256 operator""_i256(const char* str, std::size_t str_len); diff --git a/submodules/ton/tonlib-src/crypto/common/refint.cpp b/submodules/ton/tonlib-src/crypto/common/refint.cpp index 662322c62b..3a031a5a38 100644 --- a/submodules/ton/tonlib-src/crypto/common/refint.cpp +++ b/submodules/ton/tonlib-src/crypto/common/refint.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "common/refint.h" #include @@ -38,6 +38,11 @@ RefInt256 operator+(RefInt256 x, long long y) { return x; } +RefInt256 operator+(RefInt256 x, const BigInt256& y) { + (x.write() += y).normalize(); + return x; +} + RefInt256 operator-(RefInt256 x, RefInt256 y) { (x.write() -= *y).normalize(); return x; @@ -48,6 +53,11 @@ RefInt256 operator-(RefInt256 x, long long y) { return x; } +RefInt256 operator-(RefInt256 x, const BigInt256& y) { + (x.write() -= y).normalize(); + return x; +} + RefInt256 operator-(RefInt256 x) { x.write().negate().normalize(); return x; @@ -69,6 +79,12 @@ RefInt256 operator*(RefInt256 x, long long y) { return x; } +RefInt256 operator*(RefInt256 x, const BigInt256& y) { + RefInt256 z{true, 0}; + z.write().add_mul(*x, y).normalize(); + return z; +} + RefInt256 operator/(RefInt256 x, RefInt256 y) { RefInt256 quot{true}; x.write().mod_div(*y, quot.write()); @@ -142,6 +158,11 @@ RefInt256& operator+=(RefInt256& x, long long y) { return x; } +RefInt256& operator+=(RefInt256& x, const BigInt256& y) { + (x.write() += y).normalize(); + return x; +} + RefInt256& operator-=(RefInt256& x, RefInt256 y) { (x.write() -= *y).normalize(); return x; @@ -152,6 +173,11 @@ RefInt256& operator-=(RefInt256& x, long long y) { return x; } +RefInt256& operator-=(RefInt256& x, const BigInt256& y) { + (x.write() -= y).normalize(); + return x; +} + RefInt256& operator*=(RefInt256& x, RefInt256 y) { RefInt256 z{true, 0}; z.write().add_mul(*x, *y).normalize(); @@ -163,6 +189,12 @@ RefInt256& operator*=(RefInt256& x, long long y) { return x; } +RefInt256& operator*=(RefInt256& x, const BigInt256& y) { + RefInt256 z{true, 0}; + z.write().add_mul(*x, y).normalize(); + return x = z; +} + RefInt256& operator/=(RefInt256& x, RefInt256 y) { RefInt256 quot{true}; x.write().mod_div(*y, quot.write()); @@ -213,10 +245,20 @@ int sgn(RefInt256 x) { return x->sgn(); } -extern RefInt256 make_refint(long long x) { - auto xx = td::RefInt256{true, x}; - xx.unique_write().normalize(); - return xx; +RefInt256 make_refint(long long x) { + return td::RefInt256{true, td::Normalize(), x}; +} + +RefInt256 zero_refint() { + // static RefInt256 Zero = td::RefInt256{true, 0}; + // return Zero; + return td::RefInt256{true, 0}; +} + +RefInt256 bits_to_refint(td::ConstBitPtr bits, int n, bool sgnd) { + td::RefInt256 x{true}; + x.unique_write().import_bits(bits, n, sgnd); + return x; } std::string dec_string(RefInt256 x) { diff --git a/submodules/ton/tonlib-src/crypto/common/refint.h b/submodules/ton/tonlib-src/crypto/common/refint.h index a828caf162..ea1ae81b7f 100644 --- a/submodules/ton/tonlib-src/crypto/common/refint.h +++ b/submodules/ton/tonlib-src/crypto/common/refint.h @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once @@ -33,10 +33,13 @@ typedef Ref RefInt256; extern RefInt256 operator+(RefInt256 x, RefInt256 y); extern RefInt256 operator+(RefInt256 x, long long y); +extern RefInt256 operator+(RefInt256 x, const BigInt256& y); extern RefInt256 operator-(RefInt256 x, RefInt256 y); extern RefInt256 operator-(RefInt256 x, long long y); +extern RefInt256 operator-(RefInt256 x, const BigInt256& y); extern RefInt256 operator*(RefInt256 x, RefInt256 y); extern RefInt256 operator*(RefInt256 x, long long y); +extern RefInt256 operator*(RefInt256 x, const BigInt256& y); extern RefInt256 operator/(RefInt256 x, RefInt256 y); extern RefInt256 operator%(RefInt256 x, RefInt256 y); extern RefInt256 div(RefInt256 x, RefInt256 y, int round_mode = -1); @@ -53,10 +56,13 @@ extern RefInt256 rshift(RefInt256 x, int y, int round_mode = -1); extern RefInt256& operator+=(RefInt256& x, RefInt256 y); extern RefInt256& operator+=(RefInt256& x, long long y); +extern RefInt256& operator+=(RefInt256& x, const BigInt256& y); extern RefInt256& operator-=(RefInt256& x, RefInt256 y); extern RefInt256& operator-=(RefInt256& x, long long y); +extern RefInt256& operator-=(RefInt256& x, const BigInt256& y); extern RefInt256& operator*=(RefInt256& x, RefInt256 y); extern RefInt256& operator*=(RefInt256& x, long long y); +extern RefInt256& operator*=(RefInt256& x, const BigInt256& y); extern RefInt256& operator/=(RefInt256& x, RefInt256 y); extern RefInt256& operator%=(RefInt256& x, RefInt256 y); @@ -100,8 +106,16 @@ extern int cmp(RefInt256 x, RefInt256 y); extern int cmp(RefInt256 x, long long y); extern int sgn(RefInt256 x); +template +RefInt256 make_refint(Args&&... args) { + return td::RefInt256{true, std::forward(args)...}; +} + extern RefInt256 make_refint(long long x); +extern RefInt256 zero_refint(); +extern RefInt256 bits_to_refint(td::ConstBitPtr bits, int n, bool sgnd = false); + extern std::string dec_string(RefInt256 x); extern std::string dec_string2(RefInt256&& x); extern std::string hex_string(RefInt256 x, bool upcase = false); diff --git a/submodules/ton/tonlib-src/crypto/common/util.cpp b/submodules/ton/tonlib-src/crypto/common/util.cpp index 721181524d..d1b24a76bc 100644 --- a/submodules/ton/tonlib-src/crypto/common/util.cpp +++ b/submodules/ton/tonlib-src/crypto/common/util.cpp @@ -14,12 +14,15 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "util.h" #include +#include "td/utils/crypto.h" +#include "td/utils/base64.h" + namespace td { std::size_t compute_base64_encoded_size(size_t bindata_size) { @@ -73,10 +76,6 @@ std::size_t buff_base64_encode(td::MutableSlice buffer, td::Slice raw, bool base return res_size; } -std::string str_base64_encode(std::string raw, bool base64_url) { - return str_base64_encode(td::Slice{raw}, base64_url); -} - std::string str_base64_encode(td::Slice raw, bool base64_url) { std::size_t res_size = compute_base64_encoded_size(raw.size()); std::string s; @@ -87,10 +86,6 @@ std::string str_base64_encode(td::Slice raw, bool base64_url) { return s; } -bool is_valid_base64(std::string encoded, bool allow_base64_url) { - return is_valid_base64(td::Slice{encoded}, allow_base64_url); -} - bool is_valid_base64(td::Slice encoded, bool allow_base64_url) { const unsigned char *ptr = (const unsigned char *)encoded.data(), *end = ptr + encoded.size(); if (encoded.size() & 3) { @@ -110,10 +105,6 @@ bool is_valid_base64(td::Slice encoded, bool allow_base64_url) { return ptr == end; } -td::int32 decoded_base64_size(std::string encoded, bool allow_base64_url) { - return decoded_base64_size(td::Slice{encoded}, allow_base64_url); -} - td::int32 decoded_base64_size(td::Slice encoded, bool allow_base64_url) { const unsigned char *ptr = (const unsigned char *)encoded.data(), *end = ptr + encoded.size(); if (encoded.size() & 3) { @@ -172,10 +163,6 @@ std::size_t buff_base64_decode(td::MutableSlice buffer, td::Slice encoded, bool return wptr - (unsigned char *)buffer.data(); } -td::BufferSlice base64_decode(std::string encoded, bool allow_base64_url) { - return base64_decode(td::Slice{encoded}, allow_base64_url); -} - td::BufferSlice base64_decode(td::Slice encoded, bool allow_base64_url) { auto s = decoded_base64_size(encoded, allow_base64_url); if (s <= 0) { @@ -190,10 +177,6 @@ td::BufferSlice base64_decode(td::Slice encoded, bool allow_base64_url) { return res; } -std::string str_base64_decode(std::string encoded, bool allow_base64_url) { - return str_base64_decode(td::Slice{encoded}, allow_base64_url); -} - std::string str_base64_decode(td::Slice encoded, bool allow_base64_url) { auto s = decoded_base64_size(encoded, allow_base64_url); if (s <= 0) { @@ -209,4 +192,45 @@ std::string str_base64_decode(td::Slice encoded, bool allow_base64_url) { return res; } +td::Result adnl_id_encode(td::Slice id, bool upper_case) { + if (id.size() != 32) { + return td::Status::Error("Wrong andl id size"); + } + td::uint8 buf[35]; + td::MutableSlice buf_slice(buf, 35); + buf_slice[0] = 0x2d; + buf_slice.substr(1).copy_from(id); + auto hash = td::crc16(buf_slice.substr(0, 33)); + buf[33] = static_cast((hash >> 8) & 255); + buf[34] = static_cast(hash & 255); + return td::base32_encode(buf_slice, upper_case).substr(1); +} + +std::string adnl_id_encode(td::Bits256 adnl_addr, bool upper_case) { + return adnl_id_encode(adnl_addr.as_slice(), upper_case).move_as_ok(); +} + +td::Result adnl_id_decode(td::Slice id) { + if (id.size() != 55) { + return td::Status::Error("Wrong length of adnl id"); + } + td::uint8 buf[56]; + buf[0] = 'f'; + td::MutableSlice buf_slice(buf, 56); + buf_slice.substr(1).copy_from(id); + TRY_RESULT(decoded_str, td::base32_decode(buf_slice)); + auto decoded = td::Slice(decoded_str); + if (decoded[0] != 0x2d) { + return td::Status::Error("Invalid first byte"); + } + auto got_hash = (decoded.ubegin()[33] << 8) | decoded.ubegin()[34]; + auto hash = td::crc16(decoded.substr(0, 33)); + if (hash != got_hash) { + return td::Status::Error("Hash mismatch"); + } + Bits256 res; + res.as_slice().copy_from(decoded.substr(1, 32)); + return res; +} + } // namespace td diff --git a/submodules/ton/tonlib-src/crypto/common/util.h b/submodules/ton/tonlib-src/crypto/common/util.h index 2a594efc76..e6b8ec2ebb 100644 --- a/submodules/ton/tonlib-src/crypto/common/util.h +++ b/submodules/ton/tonlib-src/crypto/common/util.h @@ -14,29 +14,31 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once #include #include "td/utils/Slice.h" #include "td/utils/buffer.h" +#include "bitstring.h" + namespace td { std::size_t compute_base64_encoded_size(size_t bindata_size); std::size_t buff_base64_encode(td::MutableSlice buffer, td::Slice raw, bool base64_url = false); -std::string str_base64_encode(std::string raw, bool base64_url = false); std::string str_base64_encode(td::Slice raw, bool base64_url = false); -bool is_valid_base64(std::string encoded, bool allow_base64_url = true); bool is_valid_base64(td::Slice encoded, bool allow_base64_url = true); -td::int32 decoded_base64_size(std::string encoded, bool allow_base64_url = true); td::int32 decoded_base64_size(td::Slice encoded, bool allow_base64_url = true); std::size_t buff_base64_decode(td::MutableSlice buffer, td::Slice data, bool allow_base64_url = true); -td::BufferSlice base64_decode(std::string encoded, bool allow_base64_url = true); td::BufferSlice base64_decode(td::Slice encoded, bool allow_base64_url = true); -std::string str_base64_decode(std::string encoded, bool allow_base64_url = true); std::string str_base64_decode(td::Slice encoded, bool allow_base64_url = true); +//TODO: move it somewhere else +td::Result adnl_id_encode(td::Slice id, bool upper_case = false); +std::string adnl_id_encode(Bits256 adnl_addr, bool upper_case = false); +td::Result adnl_id_decode(td::Slice id); + } // namespace td diff --git a/submodules/ton/tonlib-src/crypto/fift/IntCtx.cpp b/submodules/ton/tonlib-src/crypto/fift/IntCtx.cpp index f2da340973..a091c04955 100644 --- a/submodules/ton/tonlib-src/crypto/fift/IntCtx.cpp +++ b/submodules/ton/tonlib-src/crypto/fift/IntCtx.cpp @@ -71,6 +71,7 @@ IntCtx::Savepoint::Savepoint(IntCtx& _ctx, std::string new_filename, std::string std::istream* new_input_stream) : ctx(_ctx) , old_line_no(_ctx.line_no) + , old_need_line(_ctx.need_line) , old_filename(_ctx.filename) , old_current_dir(_ctx.currentd_dir) , old_input_stream(_ctx.input_stream) @@ -87,6 +88,7 @@ IntCtx::Savepoint::Savepoint(IntCtx& _ctx, std::string new_filename, std::string IntCtx::Savepoint::~Savepoint() { ctx.line_no = old_line_no; + ctx.need_line = old_need_line; ctx.filename = old_filename; ctx.currentd_dir = old_current_dir; ctx.input_stream = old_input_stream; @@ -99,6 +101,7 @@ bool IntCtx::load_next_line() { if (!std::getline(*input_stream, str)) { return false; } + need_line = false; if (!str.empty() && str.back() == '\r') { str.pop_back(); } @@ -111,6 +114,7 @@ bool IntCtx::is_sb() const { } td::Slice IntCtx::scan_word_to(char delim, bool err_endl) { + load_next_line_ifreq(); auto ptr = input_ptr; while (*ptr && *ptr != delim) { ptr++; @@ -121,6 +125,7 @@ td::Slice IntCtx::scan_word_to(char delim, bool err_endl) { } else if (err_endl && delim) { throw IntError{std::string{"end delimiter `"} + delim + "` not found"}; } else { + need_line = true; std::swap(ptr, input_ptr); return td::Slice{ptr, input_ptr}; } diff --git a/submodules/ton/tonlib-src/crypto/fift/IntCtx.h b/submodules/ton/tonlib-src/crypto/fift/IntCtx.h index 1adb8f325a..b2725cdae8 100644 --- a/submodules/ton/tonlib-src/crypto/fift/IntCtx.h +++ b/submodules/ton/tonlib-src/crypto/fift/IntCtx.h @@ -68,6 +68,7 @@ struct IntCtx { int state{0}; int include_depth{0}; int line_no{0}; + bool need_line{true}; std::string filename; std::string currentd_dir; std::istream* input_stream{nullptr}; @@ -116,6 +117,9 @@ struct IntCtx { } bool load_next_line(); + bool load_next_line_ifreq() { + return need_line && load_next_line(); + } bool is_sb() const; @@ -126,6 +130,7 @@ struct IntCtx { class Savepoint { IntCtx& ctx; int old_line_no; + bool old_need_line; std::string old_filename; std::string old_current_dir; std::istream* old_input_stream; diff --git a/submodules/ton/tonlib-src/crypto/fift/fift-main.cpp b/submodules/ton/tonlib-src/crypto/fift/fift-main.cpp index 8702f13dcb..077cdeccfc 100644 --- a/submodules/ton/tonlib-src/crypto/fift/fift-main.cpp +++ b/submodules/ton/tonlib-src/crypto/fift/fift-main.cpp @@ -23,7 +23,7 @@ exception statement from your version. If you delete this exception statement from all source files in the program, then also delete it here. - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "vm/stack.hpp" #include @@ -156,7 +156,7 @@ int main(int argc, char* const argv[]) { } fift::init_words_common(config.dictionary); - fift::init_words_vm(config.dictionary); + fift::init_words_vm(config.dictionary, true); // enable vm debug fift::init_words_ton(config.dictionary); if (script_mode) { diff --git a/submodules/ton/tonlib-src/crypto/fift/lib/Asm.fif b/submodules/ton/tonlib-src/crypto/fift/lib/Asm.fif index eb9034ec1e..ced35d6fd1 100644 --- a/submodules/ton/tonlib-src/crypto/fift/lib/Asm.fif +++ b/submodules/ton/tonlib-src/crypto/fift/lib/Asm.fif @@ -165,6 +165,8 @@ x{68} @Defop DEPTH x{69} @Defop CHKDEPTH x{6A} @Defop ONLYTOPX x{6B} @Defop ONLYX +{ over 0= abort"first argument must be non-zero" + idict! + not abort"cannot add key to procedure info dictionary" + @procinfo ! +} : @procinfo! +// ( x v1 v2 -- ) +{ not 2 pick @procinfo@ and xor swap @procinfo! } : @procinfo~! +// ( s i f -- ) +{ over @procdictkeylen fits not abort"procedure index out of range" + over swap dup @procinfo~! 2dup @proclistadd + 1 'nop does swap 0 (create) } : @declproc -{ @proccnt @ 1+ dup @proccnt ! @declproc } : @newproc -{ 0 =: main @proclist null! @proccnt 0! +{ 1 'nop does swap 0 (create) } : @declglobvar +{ @proccnt @ 1+ dup @proccnt ! 1 @declproc } : @newproc +{ @gvarcnt @ 1+ dup @gvarcnt ! @declglobvar } : @newglobvar +{ 0 =: main @proclist null! @proccnt 0! @gvarcnt 0! { bl word @newproc } : NEWPROC { bl word dup (def?) ' drop ' @newproc cond } : DECLPROC { bl word dup find { nip execute <> abort"method redefined with different id" } - { swap @declproc } + { swap 17 @declproc } cond } : DECLMETHOD - "main" @proclistadd - dictnew @procdict ! + { bl word @newglobvar } : DECLGLOBVAR + "main" 0 @proclistadd + dictnew dup @procdict ! + @procinfo ! 16 0 @procinfo! } : PROGRAM{ { over sbits < { s>c } : }END> +{ }END <{ SETCP0 swap @procdictkeylen DICTPUSHCONST DICTIGETJMPZ 11 THROWARG }> } : }END> { }END> b> } : }END>c { }END>c s @@ -1116,6 +1187,14 @@ forget @proclist forget @proccnt -3 constant split_prepare -4 constant split_install +{ asm-mode 0 3 ~! } : asm-no-remove-unused +{ asm-mode 1 1 ~! } : asm-remove-unused // enabled by default +{ asm-mode 3 3 ~! } : asm-warn-remove-unused +{ asm-mode 4 4 ~! } : asm-warn-inline-mix +{ asm-mode 0 4 ~! } : asm-no-warn-inline-mix // disabled by default +{ asm-mode 8 8 ~! } : asm-warn-unused +{ asm-mode 0 8 ~! } : asm-no-warn-unused // disabled by default + // ( c -- ) add vm library for later use with runvmcode { = -rot <= and } : s-fits? +// b s x -- ? +{ swap sbitrefs -rot + rot brembitrefs -rot <= -rot <= and } : s-fits-with? { 0 swap ! } : 0! { tuck @ + swap ! } : +! { tuck @ swap - swap ! } : -! { 1 swap +! } : 1+! { -1 swap +! } : 1-! { null swap ! } : null! +{ not 2 pick @ and xor swap ! } : ~! 0 tuple constant nil { 1 tuple } : single { 2 tuple } : pair @@ -111,3 +114,20 @@ variable base { true (atom) drop } : atom { bl word atom 1 'nop } ::_ ` { hole dup 1 { @ execute } does create } : recursive +{ 0 { 1+ dup 1 ' $() does over (.) "$" swap $+ 0 (create) } rot times drop } : :$1..n +{ 10 hold } : +cr +{ 9 hold } : +tab +{ "" swap { 0 word 2dup $cmp } { rot swap $+ +cr swap } while 2drop } : scan-until-word +{ 0 word -trailing scan-until-word 1 'nop } ::_ $<< +{ 0x40 runvmx } : runvmcode +{ 0x48 runvmx } : gasrunvmcode +{ 0x43 runvmx } : runvmdict +{ 0x4b runvmx } : gasrunvmdict +{ 0x45 runvmx } : runvm +{ 0x4d runvmx } : gasrunvm +{ 0x55 runvmx } : runvmctx +{ 0x5d runvmx } : gasrunvmctx +{ 0x75 runvmx } : runvmctxact +{ 0x7d runvmx } : gasrunvmctxact +{ 0x35 runvmx } : runvmctxactq +{ 0x3d runvmx } : gasrunvmctxactq diff --git a/submodules/ton/tonlib-src/crypto/fift/lib/GetOpt.fif b/submodules/ton/tonlib-src/crypto/fift/lib/GetOpt.fif new file mode 100644 index 0000000000..442552b636 --- /dev/null +++ b/submodules/ton/tonlib-src/crypto/fift/lib/GetOpt.fif @@ -0,0 +1,131 @@ +library GetOpt // Simple command-line options parser +"Lists.fif" include + +// May be used as follows: +// begin-options +// "h" { ."Help Message" 0 halt } short-option +// "v" { parse-int =: verbosity } short-option-arg +// "i" "--interactive" { true =: interactive } short-long-option +// parse-options + +// ( l -- l') computes tail of list l if non-empty; else () +{ dup null? ' cdr ifnot } : safe-cdr +// ( l c -- l') deletes first c elements from list l +{ ' safe-cdr swap times } : list-delete-first +// ( l n c -- l' ) deletes c elements starting from n-th in list l +recursive list-delete-range { + dup 0<= { 2drop } { + over 0<= { nip list-delete-first } { + swap 1- swap rot uncons 2swap list-delete-range cons + } cond } cond +} swap ! +// ( n c -- ) deletes $n .. $(n+c-1) from the argument list $* +{ swap 1- $* @ swap rot list-delete-range $* ! } : $*del.. +// ( s s' -- ? ) checks whether s' is a prefix of s +{ tuck $len over $len over >= { $| drop $= } { 2drop drop false } cond +} : $pfx? +// ( s -- ? ) checks whether s is an option (a string beginning with '-') +{ dup $len 1 > { "-" $pfx? } { drop false } cond } : is-opt? +// ( s -- ? ) checks whether s is a digit option +{ 2 $| drop 1 $| nip $>B 8 B>u@ dup 57 <= swap 48 >= and } : is-digit-opt? +0 box constant disable-digit-opts +// ( l -- s i or 0 ) finds first string in l beginning with '-' +{ 0 { 1+ over null? { 2drop 0 true } { + swap uncons over is-opt? + { disable-digit-opts @ { over is-digit-opt? not } { true } cond } { false } cond + { drop swap true } { nip swap false } cond + } cond } until +} : list-find-opt +// ( -- s i or 0 ) finds first option in cmdline args +{ $* @ list-find-opt } : first-opt +' second : get-opt-flags +' first : get-opt-exec +// ( s t -- ? ) checks whether short/long option s matches description t +{ third $= } : short-option-matches +{ dup get-opt-flags 4 and 0= 3 + [] $= +} : long-option-matches +// ( t -- s -1 or 0 ) extracts help message from description +{ dup get-opt-flags 4 and 0= 4 + over count over > + { [] true } { 2drop false } cond +} : get-opt-help +// ( s l -- t -1 or 0 ) finds short/long option s in list l +{ swap 1 { swap short-option-matches } does assoc-gen +} : lookup-short-option +{ swap 1 { swap long-option-matches } does assoc-gen +} : lookup-long-option +// ( s -- s' null or s' s'' ) Splits long option --opt=arg at '=' +{ dup "=" $pos 1+ ?dup { tuck $| swap rot 1- $| drop swap } { null } cond +} : split-longopt +// ( l -- f or 0 ) Extracts global option flags from first entry of l +{ dup null? { drop 0 } { car get-opt-flags -256 and } cond +} : get-global-option-flags +variable options-list +// ( l -- i or 0 ) +// parses command line arguments according to option description list l +// and returns index i of first incorrect option +{ dup options-list ! get-global-option-flags + 256 and disable-digit-opts ! + { first-opt dup 0= { true } { + swap dup "--" $pfx? { // i s + dup $len 2 = { drop dup 1 $*del.. 0 true } { + split-longopt swap options-list @ + lookup-long-option not { drop true } { // i s' t f + dup get-opt-exec swap get-opt-flags 3 and // i s' e f' + 2 pick null? { dup 1 = } { dup 0= negate } cond // i s' e f' f'' + dup 1 = { 2drop 2drop true } { + { drop nip over 1+ $() swap execute 2 $*del.. false } { + ' nip ifnot execute 1 $*del.. false + } cond } cond } cond } cond } { // i s + 1 $| nip { + dup $len 0= { drop 1 $*del.. false true } { + 1 $| swap options-list @ // i s' s l + lookup-short-option not { drop true true } { // i s' t + dup get-opt-exec swap get-opt-flags 3 and // i s' e f' + ?dup 0= { execute false } { + 2 pick $len { drop execute "" false } { + 2 = { nip null swap execute "" false } { // i e + nip over 1+ $() swap execute 2 $*del.. false true + } cond } cond } cond } cond } cond } until + } cond + } cond } until +} : getopt +// ( t -- ) Displays help message for one option +{ dup get-opt-flags dup 4 and 2 pick third swap { + ."-" type ."/" over 3 [] type } { + dup $len { dup "--" $pfx? { ."-" } ifnot type } { + drop ."usage: " $0 type + } cond } cond + dup 3 and ?dup { + 2 = { ."[=]" } { ."=" } cond + } if + 8 and { 9 emit } ifnot + get-opt-help { type } { ."No help available" } cond cr +} : show-opt-help +// ( -- ) Displays options help message according to options-list +{ options-list @ { dup null? not } { + uncons swap show-opt-help + } while drop +} : show-options-help +// ( l -- ) Parses options and throws an error on failure +{ getopt ?dup { + $() "cannot parse command line options near `" swap $+ +"`" + show-options-help abort } if +} : run-getopt +anon constant opt-list-marker +' opt-list-marker : begin-options +{ opt-list-marker list-until-marker } : end-options +{ end-options run-getopt } : parse-options +// ( s e -- o ) Creates short/long option s with execution token e +{ 0 rot triple } dup : short-option : long-option +// ( s s' e -- o ) Creates a combined short option s and long option s' with execution token e +{ 4 2swap 4 tuple } : short-long-option +{ 1 rot triple } dup : short-option-arg : long-option-arg +{ 2 rot triple } dup : short-option-?arg : long-option-?arg +{ 5 2swap 4 tuple } : short-long-option-arg +{ 6 2swap 4 tuple } : short-long-option-?arg +// ( o s -- s' ) Adds help message to option +' , : option-help +// ( s f -- o ) Creates a generic help message +{ swap 'nop rot "" 3 roll 4 tuple } : generic-help-setopt +{ 0 generic-help-setopt } : generic-help +256 constant disable-digit-options diff --git a/submodules/ton/tonlib-src/crypto/fift/lib/TonUtil.fif b/submodules/ton/tonlib-src/crypto/fift/lib/TonUtil.fif index 7f1a376bb5..0e2155e178 100644 --- a/submodules/ton/tonlib-src/crypto/fift/lib/TonUtil.fif +++ b/submodules/ton/tonlib-src/crypto/fift/lib/TonUtil.fif @@ -12,6 +12,8 @@ library TonUtil // TON Blockchain Fift Library { (number) 1- abort"integer expected" } : parse-int +{ over null? ' swap if drop } : replace-if-null + // Private key load/generate // ( fname -- pubkey privkey ) { dup ."Loading private key from file " type cr @@ -32,8 +34,10 @@ library TonUtil // TON Blockchain Fift Library 1 and 0= } : parse-smc-addr +// ( x -- ) Displays a 64-digit hex number +{ 64 0x. } : 64x. // ( wc addr -- ) Show address in : form -{ swap ._ .":" 64 0x. } : .addr +{ swap ._ .":" 64x. } : .addr // ( wc addr flags -- ) Show address in base64url form { smca>$ type } : .Addr // ( wc addr fname -- ) Save address to file in 36-byte format @@ -65,6 +69,9 @@ library TonUtil // TON Blockchain Fift Library // ( b wc addr -- b' ) Serializes address into Builder b { -rot 8 i, swap 256 u, } : addr, +{ over 8 fits { rot b{100} s, -rot addr, } { + rot b{110} s, 256 9 u, rot 32 i, swap 256 u, } cond +} : Addr, // Gram utilities 1000000000 constant Gram @@ -148,3 +155,46 @@ recursive append-long-bytes { // ( x -- S ) serialize public key { 256 u>B B{3ee6} swap B+ dup crc16 16 u>B B+ B>base64 } : pubkey>$ { pubkey>$ type } : .pubkey + +// adnl address parser +{ 256 u>B B{2D} swap B+ dup crc16 16 u>B B+ } : adnl-preconv +{ swap 32 /mod dup 26 < { 65 } { 24 } cond + rot swap hold } : Base32# +{ <# ' Base32# 8 times #> } : Base32#*8 +{ "" over Blen 5 / { swap 40 B>u@+ Base32#*8 nip rot swap $+ } swap times nip } : B>Base32 + +// ( x -- S ) Converts an adnl-address from a 256-bit integer to a string +{ adnl-preconv B>Base32 1 $| nip } : adnl>$ + +{ 65 - dup 0>= { -33 and dup 26 < } { 41 + dup 25 > over 32 < and } cond ?dup nip } : Base32-digit? +{ Base32-digit? not abort"not a Base32 digit" } : Base32-digit +{ 0 { over $len } { swap 1 $| -rot (char) Base32-digit swap 5 << + } while nip } : Base32-number +{ B{} { over $len } { swap 8 $| -rot Base32-number 40 u>B B+ } while nip } : Base32>B + +// ( S -- x ) Converts an adnl address from a string to 256-bit integer +{ dup $len 55 <> abort"not 55 alphanumeric characters" "F" swap $+ Base32>B + 33 B| 16 B>u@ over crc16 <> abort"crc16 checksum mismatch" + 8 B>u@+ 0x2D <> abort"not a valid adnl address" 256 B>u@ } : $>adnl + +{ 65 - dup 0>= { -33 and 10 + dup 16 < } { 17 + dup 0>= over 10 < and } cond ?dup nip } : hex-digit? +// ( S -- x -1 or 0 ) Parses a hexadecimal integer +{ dup $len { + 0 { + 4 << swap 1 $| -rot (char) hex-digit? // S a d -1 or S a 0 + { + over $len 0= } { drop -1 true } cond + } until + dup 0< { 2drop false } { nip true } cond + } { drop false } cond +} : hex$>u? +// ( S -- x ) +{ hex$>u? not abort"not a hexadecimal number" } : hex$>u + +{ dup $len 64 = { hex$>u } { + dup $len 55 = { $>adnl } { + true abort"invalid adnl address" + } cond } cond +} : parse-adnl-addr +{ adnl>$ type } : .adnl +{ bl word parse-adnl-addr 1 'nop } ::_ adnl: + +// ( x a b -- a<=x<=b ) +{ 2 pick >= -rot >= and } : in-range? diff --git a/submodules/ton/tonlib-src/crypto/fift/utils.cpp b/submodules/ton/tonlib-src/crypto/fift/utils.cpp index fdbd0c7eef..3ed11c31b6 100644 --- a/submodules/ton/tonlib-src/crypto/fift/utils.cpp +++ b/submodules/ton/tonlib-src/crypto/fift/utils.cpp @@ -46,6 +46,9 @@ td::Result load_Lists_fif(std::string dir = "") { td::Result load_Lisp_fif(std::string dir = "") { return load_source("Lisp.fif", dir); } +td::Result load_GetOpt_fif(std::string dir = "") { + return load_source("GetOpt.fif", dir); +} class MemoryFileLoader : public fift::FileLoader { public: @@ -115,6 +118,10 @@ td::Result create_source_lookup(std::string main, bool need_ TRY_RESULT(f, load_TonUtil_fif(dir)); loader->add_file("/TonUtil.fif", std::move(f)); } + { + TRY_RESULT(f, load_GetOpt_fif(dir)); + loader->add_file("/GetOpt.fif", std::move(f)); + } } if (need_lisp) { TRY_RESULT(f, load_Lisp_fif(dir)); diff --git a/submodules/ton/tonlib-src/crypto/fift/words.cpp b/submodules/ton/tonlib-src/crypto/fift/words.cpp index 2c1a3083d6..3afd687ec4 100644 --- a/submodules/ton/tonlib-src/crypto/fift/words.cpp +++ b/submodules/ton/tonlib-src/crypto/fift/words.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "words.h" @@ -32,7 +32,7 @@ #include "vm/cells.h" #include "vm/cellslice.h" -#include "vm/continuation.h" +#include "vm/vm.h" #include "vm/cp0.h" #include "vm/dict.h" #include "vm/boc.h" @@ -96,6 +96,10 @@ void interpret_dotstack_list(IntCtx& ctx) { *ctx.output_stream << std::endl; } +void interpret_dotstack_list_dump(IntCtx& ctx) { + ctx.stack.dump(*ctx.output_stream, 3); +} + void interpret_dump(IntCtx& ctx) { ctx.stack.pop_chk().dump(*ctx.output_stream); *ctx.output_stream << ' '; @@ -105,6 +109,10 @@ void interpret_dump_internal(vm::Stack& stack) { stack.push_string(stack.pop_chk().to_string()); } +void interpret_list_dump_internal(vm::Stack& stack) { + stack.push_string(stack.pop_chk().to_lisp_string()); +} + void interpret_print_list(IntCtx& ctx) { ctx.stack.pop_chk().print_list(*ctx.output_stream); *ctx.output_stream << ' '; @@ -172,9 +180,9 @@ void interpret_times_div(vm::Stack& stack, int round_mode) { auto z = stack.pop_int(); auto y = stack.pop_int(); auto x = stack.pop_int(); - td::BigIntG<257 * 2> tmp{0}; + typename td::BigInt256::DoubleInt tmp{0}; tmp.add_mul(*x, *y); - auto q = td::RefInt256{true}; + auto q = td::make_refint(); tmp.mod_div(*z, q.unique_write(), round_mode); q.unique_write().normalize(); stack.push_int(std::move(q)); @@ -184,26 +192,23 @@ void interpret_times_divmod(vm::Stack& stack, int round_mode) { auto z = stack.pop_int(); auto y = stack.pop_int(); auto x = stack.pop_int(); - td::BigIntG<257 * 2> tmp{0}; + typename td::BigInt256::DoubleInt tmp{0}; tmp.add_mul(*x, *y); - auto q = td::RefInt256{true}; + auto q = td::make_refint(); tmp.mod_div(*z, q.unique_write(), round_mode); q.unique_write().normalize(); - auto r = td::RefInt256{true, tmp}; stack.push_int(std::move(q)); - stack.push_int(std::move(r)); + stack.push_int(td::make_refint(tmp)); } void interpret_times_mod(vm::Stack& stack, int round_mode) { auto z = stack.pop_int(); auto y = stack.pop_int(); auto x = stack.pop_int(); - td::BigIntG<257 * 2> tmp{0}; + typename td::BigInt256::DoubleInt tmp{0}, q; tmp.add_mul(*x, *y); - td::BigIntG<257 * 2> q; tmp.mod_div(*z, q, round_mode); - auto r = td::RefInt256{true, tmp}; - stack.push_int(std::move(r)); + stack.push_int(td::make_refint(tmp)); } void interpret_negate(vm::Stack& stack) { @@ -245,21 +250,21 @@ void interpret_fits(vm::Stack& stack, bool sgnd) { void interpret_pow2(vm::Stack& stack) { int x = stack.pop_smallint_range(255); - auto r = td::RefInt256{true}; + auto r = td::make_refint(); r.unique_write().set_pow2(x); stack.push_int(r); } void interpret_neg_pow2(vm::Stack& stack) { int x = stack.pop_smallint_range(256); - auto r = td::RefInt256{true}; + auto r = td::make_refint(); r.unique_write().set_pow2(x).negate().normalize(); stack.push_int(r); } void interpret_pow2_minus1(vm::Stack& stack) { int x = stack.pop_smallint_range(256); - auto r = td::RefInt256{true}; + auto r = td::make_refint(); r.unique_write().set_pow2(x).add_tiny(-1).normalize(); stack.push_int(r); } @@ -293,19 +298,18 @@ void interpret_times_rshift(vm::Stack& stack, int round_mode) { int z = stack.pop_smallint_range(256); auto y = stack.pop_int(); auto x = stack.pop_int(); - td::BigIntG<257 * 2> tmp{0}; + typename td::BigInt256::DoubleInt tmp{0}; tmp.add_mul(*x, *y).rshift(z, round_mode).normalize(); - auto q = td::RefInt256{true, tmp}; - stack.push_int(std::move(q)); + stack.push_int(td::make_refint(tmp)); } void interpret_lshift_div(vm::Stack& stack, int round_mode) { int z = stack.pop_smallint_range(256); auto y = stack.pop_int(); auto x = stack.pop_int(); - td::BigIntG<257 * 2> tmp{*x}; + typename td::BigInt256::DoubleInt tmp{*x}; tmp <<= z; - auto q = td::RefInt256{true}; + auto q = td::make_refint(); tmp.mod_div(*y, q.unique_write(), round_mode); q.unique_write().normalize(); stack.push_int(std::move(q)); @@ -596,6 +600,12 @@ void interpret_str_split(vm::Stack& stack) { stack.push_string(std::string{str, sz}); } +void interpret_str_pos(vm::Stack& stack) { + auto s2 = stack.pop_string(), s1 = stack.pop_string(); + auto pos = s1.find(s2); + stack.push_smallint(pos == std::string::npos ? -1 : pos); +} + void interpret_str_reverse(vm::Stack& stack) { std::string s = stack.pop_string(); auto it = s.begin(); @@ -651,6 +661,20 @@ void interpret_utf8_str_split(vm::Stack& stack) { } } +void interpret_utf8_str_pos(vm::Stack& stack) { + auto s2 = stack.pop_string(), s1 = stack.pop_string(); + auto pos = s1.find(s2); + if (pos == std::string::npos) { + stack.push_smallint(-1); + return; + } + int cnt = 0; + for (std::size_t i = 0; i < pos; i++) { + cnt += ((s1[i] & 0xc0) != 0x80); + } + stack.push_smallint(cnt); +} + void interpret_str_remove_trailing_int(vm::Stack& stack, int arg) { char x = (char)(arg ? arg : stack.pop_long_range(127)); std::string s = stack.pop_string(); @@ -979,8 +1003,8 @@ void interpret_store_end(vm::Stack& stack, bool special) { void interpret_from_cell(vm::Stack& stack) { auto cell = stack.pop_cell(); - Ref cs{true}; - if (!cs.unique_write().load(vm::NoVmOrd(), std::move(cell))) { + Ref cs{true, vm::NoVmOrd(), std::move(cell)}; + if (!cs->is_valid()) { throw IntError{"deserializing a special cell as ordinary"}; } stack.push(cs); @@ -1089,7 +1113,10 @@ void interpret_fetch_ref(vm::Stack& stack, int mode) { stack.push(std::move(cs)); } if (mode & 1) { - Ref new_cs{true, vm::NoVm(), std::move(cell)}; + Ref new_cs{true, vm::NoVmOrd(), std::move(cell)}; + if (!new_cs->is_valid()) { + throw IntError{"cannot load ordinary cell"}; + } stack.push(std::move(new_cs)); } else { stack.push_cell(std::move(cell)); @@ -1484,11 +1511,12 @@ void interpret_store_dict(vm::Stack& stack) { } // val key dict keylen -- dict' ? -void interpret_dict_add_u(vm::Stack& stack, vm::Dictionary::SetMode mode, bool add_builder, bool sgnd) { +void interpret_dict_add(vm::Stack& stack, vm::Dictionary::SetMode mode, bool add_builder, int sgnd) { int n = stack.pop_smallint_range(vm::Dictionary::max_key_bits); vm::Dictionary dict{stack.pop_maybe_cell(), n}; unsigned char buffer[vm::Dictionary::max_key_bytes]; - vm::BitSlice key = dict.integer_key(stack.pop_int(), n, sgnd, buffer); + vm::BitSlice key = + (sgnd >= 0) ? dict.integer_key(stack.pop_int(), n, sgnd, buffer) : stack.pop_cellslice()->prefetch_bits(n); if (!key.is_valid()) { throw IntError{"not enough bits for a dictionary key"}; } @@ -1502,81 +1530,91 @@ void interpret_dict_add_u(vm::Stack& stack, vm::Dictionary::SetMode mode, bool a stack.push_bool(res); } -void interpret_dict_get_u(vm::Stack& stack, bool sgnd) { +void interpret_dict_get(vm::Stack& stack, int sgnd, int mode) { int n = stack.pop_smallint_range(vm::Dictionary::max_key_bits); vm::Dictionary dict{stack.pop_maybe_cell(), n}; unsigned char buffer[vm::Dictionary::max_key_bytes]; - vm::BitSlice key = dict.integer_key(stack.pop_int(), n, sgnd, buffer); + vm::BitSlice key = + (sgnd >= 0) ? dict.integer_key(stack.pop_int(), n, sgnd, buffer) : stack.pop_cellslice()->prefetch_bits(n); if (!key.is_valid()) { throw IntError{"not enough bits for a dictionary key"}; } - auto res = dict.lookup(std::move(key)); - if (res.not_null()) { + auto res = (mode & 4 ? dict.lookup_delete(std::move(key)) : dict.lookup(std::move(key))); + if (mode & 4) { + stack.push_maybe_cell(std::move(dict).extract_root_cell()); + } + bool found = res.not_null(); + if (found && (mode & 2)) { stack.push_cellslice(std::move(res)); - stack.push_bool(true); - } else { - stack.push_bool(false); + } + if (mode & 1) { + stack.push_bool(found); } } -void interpret_dict_map(IntCtx& ctx) { +void interpret_dict_map(IntCtx& ctx, bool ext, bool sgnd) { auto func = pop_exec_token(ctx); int n = ctx.stack.pop_smallint_range(vm::Dictionary::max_key_bits); - vm::Dictionary dict{ctx.stack.pop_maybe_cell(), n}; - vm::Dictionary::simple_map_func_t simple_map = [&ctx, func](vm::CellBuilder& cb, Ref cs_ref) -> bool { - ctx.stack.push_builder(Ref(cb)); - ctx.stack.push_cellslice(std::move(cs_ref)); - func->run(ctx); - assert(cb.is_unique()); - if (!ctx.stack.pop_bool()) { - return false; + vm::Dictionary dict{ctx.stack.pop_maybe_cell(), n}, dict2{n}; + for (auto entry : dict.range(false, sgnd)) { + ctx.stack.push_builder(Ref{true}); + if (ext) { + ctx.stack.push_int(dict.key_as_integer(entry.first, sgnd)); + } + ctx.stack.push_cellslice(std::move(entry.second)); + func->run(ctx); + if (ctx.stack.pop_bool()) { + if (!dict2.set_builder(entry.first, n, ctx.stack.pop_builder())) { + throw IntError{"cannot insert value into dictionary"}; + } } - Ref cb_ref = ctx.stack.pop_builder(); - cb = *cb_ref; - return true; }; - dict.map(std::move(simple_map)); - ctx.stack.push_maybe_cell(std::move(dict).extract_root_cell()); + ctx.stack.push_maybe_cell(std::move(dict2).extract_root_cell()); } -void interpret_dict_map_ext(IntCtx& ctx) { +void interpret_dict_foreach(IntCtx& ctx, bool reverse, bool sgnd) { auto func = pop_exec_token(ctx); int n = ctx.stack.pop_smallint_range(vm::Dictionary::max_key_bits); vm::Dictionary dict{ctx.stack.pop_maybe_cell(), n}; - vm::Dictionary::map_func_t map_func = [&ctx, func](vm::CellBuilder& cb, Ref cs_ref, - td::ConstBitPtr key, int key_len) -> bool { - ctx.stack.push_builder(Ref(cb)); - td::RefInt256 x{true}; - x.unique_write().import_bits(key, key_len, false); - ctx.stack.push_int(std::move(x)); - ctx.stack.push_cellslice(std::move(cs_ref)); + for (auto entry : dict.range(reverse, sgnd)) { + ctx.stack.push_int(dict.key_as_integer(entry.first, sgnd)); + ctx.stack.push_cellslice(std::move(entry.second)); func->run(ctx); - assert(cb.is_unique()); if (!ctx.stack.pop_bool()) { - return false; + ctx.stack.push_bool(false); + return; } - Ref cb_ref = ctx.stack.pop_builder(); - cb = *cb_ref; - return true; }; - dict.map(std::move(map_func)); - ctx.stack.push_maybe_cell(std::move(dict).extract_root_cell()); + ctx.stack.push_bool(true); } -void interpret_dict_foreach(IntCtx& ctx) { +// mode: +1 = reverse, +2 = signed, +4 = strict, +8 = lookup backwards, +16 = with hint +void interpret_dict_foreach_from(IntCtx& ctx, int mode) { + if (mode < 0) { + mode = ctx.stack.pop_smallint_range(31); + } auto func = pop_exec_token(ctx); int n = ctx.stack.pop_smallint_range(vm::Dictionary::max_key_bits); vm::Dictionary dict{ctx.stack.pop_maybe_cell(), n}; - vm::Dictionary::foreach_func_t foreach_func = [&ctx, func](Ref cs_ref, td::ConstBitPtr key, - int key_len) -> bool { - td::RefInt256 x{true}; - x.unique_write().import_bits(key, key_len, false); - ctx.stack.push_int(std::move(x)); - ctx.stack.push_cellslice(std::move(cs_ref)); + vm::DictIterator it{dict, mode & 3}; + unsigned char buffer[vm::Dictionary::max_key_bytes]; + for (int s = (mode >> 4) & 1; s >= 0; --s) { + auto key = dict.integer_key(ctx.stack.pop_int(), n, mode & 2, buffer); + if (!key.is_valid()) { + throw IntError{"not enough bits for a dictionary key"}; + } + it.lookup(key, mode & 4, mode & 8); + } + for (; !it.eof(); ++it) { + ctx.stack.push_int(dict.key_as_integer(it.cur_pos(), mode & 2)); + ctx.stack.push_cellslice(it.cur_value()); func->run(ctx); - return ctx.stack.pop_bool(); + if (!ctx.stack.pop_bool()) { + ctx.stack.push_bool(false); + return; + } }; - ctx.stack.push_bool(dict.check_for_each(std::move(foreach_func))); + ctx.stack.push_bool(true); } void interpret_dict_merge(IntCtx& ctx) { @@ -1584,24 +1622,33 @@ void interpret_dict_merge(IntCtx& ctx) { int n = ctx.stack.pop_smallint_range(vm::Dictionary::max_key_bits); vm::Dictionary dict2{ctx.stack.pop_maybe_cell(), n}; vm::Dictionary dict1{ctx.stack.pop_maybe_cell(), n}; - vm::Dictionary::simple_combine_func_t simple_combine = [&ctx, func](vm::CellBuilder& cb, Ref cs1_ref, - Ref cs2_ref) -> bool { - ctx.stack.push_builder(Ref(cb)); - ctx.stack.push_cellslice(std::move(cs1_ref)); - ctx.stack.push_cellslice(std::move(cs2_ref)); - func->run(ctx); - assert(cb.is_unique()); - if (!ctx.stack.pop_bool()) { - return false; + vm::Dictionary dict3{n}; + auto it1 = dict1.begin(), it2 = dict2.begin(); + while (!it1.eof() || !it2.eof()) { + int c = it1.eof() ? 1 : (it2.eof() ? -1 : it1.cur_pos().compare(it2.cur_pos(), n)); + bool ok = true; + if (c < 0) { + ok = dict3.set(it1.cur_pos(), n, it1.cur_value()); + ++it1; + } else if (c > 0) { + ok = dict3.set(it2.cur_pos(), n, it2.cur_value()); + ++it2; + } else { + ctx.stack.push_builder(Ref{true}); + ctx.stack.push_cellslice(it1.cur_value()); + ctx.stack.push_cellslice(it2.cur_value()); + func->run(ctx); + if (ctx.stack.pop_bool()) { + ok = dict3.set_builder(it1.cur_pos(), n, ctx.stack.pop_builder()); + } + ++it1; + ++it2; + } + if (!ok) { + throw IntError{"cannot insert value into dictionary"}; } - Ref cb_ref = ctx.stack.pop_builder(); - cb = *cb_ref; - return true; - }; - if (!dict1.combine_with(dict2, std::move(simple_combine))) { - throw IntError{"cannot combine dictionaries"}; } - ctx.stack.push_maybe_cell(std::move(dict1).extract_root_cell()); + ctx.stack.push_maybe_cell(std::move(dict3).extract_root_cell()); } void interpret_dict_diff(IntCtx& ctx) { @@ -1609,17 +1656,40 @@ void interpret_dict_diff(IntCtx& ctx) { int n = ctx.stack.pop_smallint_range(vm::Dictionary::max_key_bits); vm::Dictionary dict2{ctx.stack.pop_maybe_cell(), n}; vm::Dictionary dict1{ctx.stack.pop_maybe_cell(), n}; - vm::Dictionary::scan_diff_func_t scan_value_pair = - [&ctx, func](td::ConstBitPtr key, int key_len, Ref cs1_ref, Ref cs2_ref) -> bool { - td::RefInt256 x{true}; - x.unique_write().import_bits(key, key_len, false); - ctx.stack.push_int(std::move(x)); - ctx.stack.push_maybe_cellslice(std::move(cs1_ref)); - ctx.stack.push_maybe_cellslice(std::move(cs2_ref)); - func->run(ctx); - return ctx.stack.pop_bool(); - }; - ctx.stack.push_bool(dict1.scan_diff(dict2, std::move(scan_value_pair))); + auto it1 = dict1.begin(), it2 = dict2.begin(); + while (!it1.eof() || !it2.eof()) { + int c = it1.eof() ? 1 : (it2.eof() ? -1 : it1.cur_pos().compare(it2.cur_pos(), n)); + bool run = true; + if (c < 0) { + ctx.stack.push_int(dict1.key_as_integer(it1.cur_pos())); + ctx.stack.push_cellslice(it1.cur_value()); + ctx.stack.push_null(); + ++it1; + } else if (c > 0) { + ctx.stack.push_int(dict2.key_as_integer(it2.cur_pos())); + ctx.stack.push_null(); + ctx.stack.push_cellslice(it2.cur_value()); + ++it2; + } else { + if (!it1.cur_value()->contents_equal(*it2.cur_value())) { + ctx.stack.push_int(dict1.key_as_integer(it1.cur_pos())); + ctx.stack.push_cellslice(it1.cur_value()); + ctx.stack.push_cellslice(it2.cur_value()); + } else { + run = false; + } + ++it1; + ++it2; + } + if (run) { + func->run(ctx); + if (!ctx.stack.pop_bool()) { + ctx.stack.push_bool(false); + return; + } + } + } + ctx.stack.push_bool(true); } void interpret_pfx_dict_add(vm::Stack& stack, vm::Dictionary::SetMode mode, bool add_builder) { @@ -1858,7 +1928,7 @@ int parse_number(std::string s, td::RefInt256& num, td::RefInt256& denom, bool a const char* str = s.c_str(); int len = (int)s.size(); int frac = -1, base, *frac_ptr = allow_frac ? &frac : nullptr; - num = td::RefInt256{true}; + num = td::make_refint(); auto& x = num.unique_write(); if (len >= 4 && str[0] == '-' && str[1] == '0' && (str[2] == 'x' || str[2] == 'b')) { if (str[2] == 'x') { @@ -1900,7 +1970,7 @@ int parse_number(std::string s, td::RefInt256& num, td::RefInt256& denom, bool a if (frac < 0) { return 1; } else { - denom = td::RefInt256{true, 1}; + denom = td::make_refint(1); while (frac-- > 0) { if (!denom.unique_write().mul_tiny(base).normalize_bool()) { if (throw_error) { @@ -2141,6 +2211,7 @@ class StringLogger : public td::LogInterface { } std::string res; }; + class OstreamLogger : public td::LogInterface { public: explicit OstreamLogger(std::ostream* stream) : stream_(stream) { @@ -2163,59 +2234,42 @@ std::vector> get_vm_libraries() { } } -void interpret_run_vm_code(IntCtx& ctx, bool with_gas) { - long long gas_limit = with_gas ? ctx.stack.pop_long_range(vm::GasLimits::infty) : vm::GasLimits::infty; - auto cs = ctx.stack.pop_cellslice(); - OstreamLogger ostream_logger(ctx.error_stream); - auto log = create_vm_log(ctx.error_stream ? &ostream_logger : nullptr); - vm::GasLimits gas{gas_limit}; - int res = vm::run_vm_code(cs, ctx.stack, 0, nullptr, log, nullptr, &gas, get_vm_libraries()); - ctx.stack.push_smallint(res); - if (with_gas) { - ctx.stack.push_smallint(gas.gas_consumed()); +// mode: -1 = pop from stack +// +1 = same_c3 (set c3 to code) +// +2 = push_0 (push an implicit 0 before running the code) +// +4 = load c4 (persistent data) from stack and return its final value +// +8 = load gas limit from stack and return consumed gas +// +16 = load c7 (smart-contract context) +// +32 = return c5 (actions) +// +64 = log vm ops to stderr +void interpret_run_vm(IntCtx& ctx, int mode) { + if (mode < 0) { + mode = ctx.stack.pop_smallint_range(0xff); } -} - -void interpret_run_vm_dict(IntCtx& ctx, bool with_gas) { - long long gas_limit = with_gas ? ctx.stack.pop_long_range(vm::GasLimits::infty) : vm::GasLimits::infty; - auto cs = ctx.stack.pop_cellslice(); - OstreamLogger ostream_logger(ctx.error_stream); - auto log = create_vm_log(ctx.error_stream ? &ostream_logger : nullptr); - vm::GasLimits gas{gas_limit}; - int res = vm::run_vm_code(cs, ctx.stack, 3, nullptr, log, nullptr, &gas, get_vm_libraries()); - ctx.stack.push_smallint(res); - if (with_gas) { - ctx.stack.push_smallint(gas.gas_consumed()); + bool with_data = mode & 4; + Ref c7; + Ref data, actions; + long long gas_limit = (mode & 8) ? ctx.stack.pop_long_range(vm::GasLimits::infty) : vm::GasLimits::infty; + if (mode & 16) { + c7 = ctx.stack.pop_tuple(); } -} - -void interpret_run_vm(IntCtx& ctx, bool with_gas) { - long long gas_limit = with_gas ? ctx.stack.pop_long_range(vm::GasLimits::infty) : vm::GasLimits::infty; - auto data = ctx.stack.pop_cell(); - auto cs = ctx.stack.pop_cellslice(); - OstreamLogger ostream_logger(ctx.error_stream); - auto log = create_vm_log(ctx.error_stream ? &ostream_logger : nullptr); - vm::GasLimits gas{gas_limit}; - int res = vm::run_vm_code(cs, ctx.stack, 1, &data, log, nullptr, &gas, get_vm_libraries()); - ctx.stack.push_smallint(res); - ctx.stack.push_cell(std::move(data)); - if (with_gas) { - ctx.stack.push_smallint(gas.gas_consumed()); + if (with_data) { + data = ctx.stack.pop_cell(); } -} - -void interpret_run_vm_c7(IntCtx& ctx, bool with_gas) { - long long gas_limit = with_gas ? ctx.stack.pop_long_range(vm::GasLimits::infty) : vm::GasLimits::infty; - auto c7 = ctx.stack.pop_tuple(); - auto data = ctx.stack.pop_cell(); auto cs = ctx.stack.pop_cellslice(); OstreamLogger ostream_logger(ctx.error_stream); - auto log = create_vm_log(ctx.error_stream ? &ostream_logger : nullptr); + auto log = create_vm_log((mode & 64) && ctx.error_stream ? &ostream_logger : nullptr); vm::GasLimits gas{gas_limit}; - int res = vm::run_vm_code(cs, ctx.stack, 1, &data, log, nullptr, &gas, get_vm_libraries(), std::move(c7)); + int res = + vm::run_vm_code(cs, ctx.stack, mode & 3, &data, log, nullptr, &gas, get_vm_libraries(), std::move(c7), &actions); ctx.stack.push_smallint(res); - ctx.stack.push_cell(std::move(data)); - if (with_gas) { + if (with_data) { + ctx.stack.push_cell(std::move(data)); + } + if (mode & 32) { + ctx.stack.push_cell(std::move(actions)); + } + if (mode & 8) { ctx.stack.push_smallint(gas.gas_consumed()); } } @@ -2328,12 +2382,57 @@ void interpret_db_run_vm_parallel(IntCtx& ctx) { do_interpret_db_run_vm_parallel(ctx.error_stream, ctx.stack, ctx.ton_db, threads_n, tasks_n); } +void interpret_store_vm_cont(vm::Stack& stack) { + auto vmcont = stack.pop_cont(); + auto cb = stack.pop_builder(); + if (!vmcont->serialize(cb.write())) { + throw IntError{"cannot serialize vm continuation"}; + } + stack.push_builder(std::move(cb)); +} + +void interpret_fetch_vm_cont(vm::Stack& stack) { + auto cs = stack.pop_cellslice(); + auto vmcont = vm::Continuation::deserialize(cs.write()); + if (vmcont.is_null()) { + throw IntError{"cannot deserialize vm continuation"}; + } + stack.push_cellslice(std::move(cs)); + stack.push_cont(std::move(vmcont)); +} + +Ref cmdline_args{true}; + +void interpret_get_fixed_cmdline_arg(vm::Stack& stack, int n) { + if (!n) { + return; + } + auto v = cmdline_args->get(); + while (true) { + if (v.empty()) { + stack.push(vm::StackEntry{}); + return; + } + auto t = v.as_tuple_range(2, 2); + if (t.is_null()) { + throw IntError{"invalid cmdline arg list"}; + } + if (!--n) { + stack.push(t->at(0)); + return; + } + v = t->at(1); + } +} + // n -- executes $n void interpret_get_cmdline_arg(IntCtx& ctx) { int n = ctx.stack.pop_smallint_range(999999); - char buffer[14]; - sprintf(buffer, "$%d ", n); - auto entry = ctx.dictionary->lookup(std::string{buffer}); + if (n) { + interpret_get_fixed_cmdline_arg(ctx.stack, n); + return; + } + auto entry = ctx.dictionary->lookup("$0 "); if (!entry) { throw IntError{"-?"}; } else { @@ -2341,6 +2440,19 @@ void interpret_get_cmdline_arg(IntCtx& ctx) { } } +void interpret_get_cmdline_arg_count(vm::Stack& stack) { + auto v = cmdline_args->get(); + int cnt; + for (cnt = 0; !v.empty(); cnt++) { + auto t = v.as_tuple_range(2, 2); + if (t.is_null()) { + throw IntError{"invalid cmdline arg list"}; + } + v = t->at(1); + } + stack.push_smallint(cnt); +} + void interpret_getenv(vm::Stack& stack) { auto str = stack.pop_string(); auto value = str.size() < 1024 ? getenv(str.c_str()) : nullptr; @@ -2434,10 +2546,12 @@ void init_words_common(Dictionary& d) { d.def_ctx_word("csr. ", interpret_dot_cellslice_rec); d.def_ctx_word(".s ", interpret_dotstack); d.def_ctx_word(".sl ", interpret_dotstack_list); + d.def_ctx_word(".sL ", interpret_dotstack_list_dump); // TMP d.def_ctx_word(".dump ", interpret_dump); d.def_ctx_word(".l ", interpret_print_list); d.def_ctx_word(".tc ", interpret_dottc); d.def_stack_word("(dump) ", interpret_dump_internal); + d.def_stack_word("(ldump) ", interpret_list_dump_internal); d.def_stack_word("(.) ", interpret_dot_internal); d.def_stack_word("(x.) ", std::bind(interpret_dothex_internal, _1, false)); d.def_stack_word("(X.) ", std::bind(interpret_dothex_internal, _1, true)); @@ -2558,6 +2672,7 @@ void init_words_common(Dictionary& d) { d.def_stack_word("$= ", interpret_str_equal); d.def_stack_word("$cmp ", interpret_str_cmp); d.def_stack_word("$reverse ", interpret_str_reverse); + d.def_stack_word("$pos ", interpret_str_pos); d.def_stack_word("(-trailing) ", std::bind(interpret_str_remove_trailing_int, _1, 0)); d.def_stack_word("-trailing ", std::bind(interpret_str_remove_trailing_int, _1, ' ')); d.def_stack_word("-trailing0 ", std::bind(interpret_str_remove_trailing_int, _1, '0')); @@ -2565,6 +2680,7 @@ void init_words_common(Dictionary& d) { d.def_stack_word("Blen ", interpret_bytes_len); d.def_stack_word("$Len ", interpret_utf8_str_len); d.def_stack_word("$Split ", interpret_utf8_str_split); + d.def_stack_word("$Pos ", interpret_utf8_str_pos); d.def_ctx_word("Bx. ", std::bind(interpret_bytes_hex_print_raw, _1, true)); d.def_stack_word("B>X ", std::bind(interpret_bytes_to_hex, _1, true)); d.def_stack_word("B>x ", std::bind(interpret_bytes_to_hex, _1, false)); @@ -2669,22 +2785,38 @@ void init_words_common(Dictionary& d) { d.def_stack_word("dict, ", interpret_store_dict); d.def_stack_word("dict@ ", std::bind(interpret_load_dict, _1, false)); d.def_stack_word("dict@+ ", std::bind(interpret_load_dict, _1, true)); - d.def_stack_word("udict!+ ", std::bind(interpret_dict_add_u, _1, vm::Dictionary::SetMode::Add, false, false)); - d.def_stack_word("udict! ", std::bind(interpret_dict_add_u, _1, vm::Dictionary::SetMode::Set, false, false)); - d.def_stack_word("b>udict!+ ", std::bind(interpret_dict_add_u, _1, vm::Dictionary::SetMode::Add, true, false)); - d.def_stack_word("b>udict! ", std::bind(interpret_dict_add_u, _1, vm::Dictionary::SetMode::Set, true, false)); - d.def_stack_word("udict@ ", std::bind(interpret_dict_get_u, _1, false)); - d.def_stack_word("idict!+ ", std::bind(interpret_dict_add_u, _1, vm::Dictionary::SetMode::Add, false, true)); - d.def_stack_word("idict! ", std::bind(interpret_dict_add_u, _1, vm::Dictionary::SetMode::Set, false, true)); - d.def_stack_word("b>idict!+ ", std::bind(interpret_dict_add_u, _1, vm::Dictionary::SetMode::Add, true, true)); - d.def_stack_word("b>idict! ", std::bind(interpret_dict_add_u, _1, vm::Dictionary::SetMode::Set, true, true)); - d.def_stack_word("idict@ ", std::bind(interpret_dict_get_u, _1, true)); + d.def_stack_word("sdict!+ ", std::bind(interpret_dict_add, _1, vm::Dictionary::SetMode::Add, false, -1)); + d.def_stack_word("sdict! ", std::bind(interpret_dict_add, _1, vm::Dictionary::SetMode::Set, false, -1)); + d.def_stack_word("b>sdict!+ ", std::bind(interpret_dict_add, _1, vm::Dictionary::SetMode::Add, true, -1)); + d.def_stack_word("b>sdict! ", std::bind(interpret_dict_add, _1, vm::Dictionary::SetMode::Set, true, -1)); + d.def_stack_word("sdict@ ", std::bind(interpret_dict_get, _1, -1, 3)); + d.def_stack_word("sdict@- ", std::bind(interpret_dict_get, _1, -1, 7)); + d.def_stack_word("sdict- ", std::bind(interpret_dict_get, _1, -1, 5)); + d.def_stack_word("udict!+ ", std::bind(interpret_dict_add, _1, vm::Dictionary::SetMode::Add, false, 0)); + d.def_stack_word("udict! ", std::bind(interpret_dict_add, _1, vm::Dictionary::SetMode::Set, false, 0)); + d.def_stack_word("b>udict!+ ", std::bind(interpret_dict_add, _1, vm::Dictionary::SetMode::Add, true, 0)); + d.def_stack_word("b>udict! ", std::bind(interpret_dict_add, _1, vm::Dictionary::SetMode::Set, true, 0)); + d.def_stack_word("udict@ ", std::bind(interpret_dict_get, _1, 0, 3)); + d.def_stack_word("udict@- ", std::bind(interpret_dict_get, _1, 0, 7)); + d.def_stack_word("udict- ", std::bind(interpret_dict_get, _1, 0, 5)); + d.def_stack_word("idict!+ ", std::bind(interpret_dict_add, _1, vm::Dictionary::SetMode::Add, false, 1)); + d.def_stack_word("idict! ", std::bind(interpret_dict_add, _1, vm::Dictionary::SetMode::Set, false, 1)); + d.def_stack_word("b>idict!+ ", std::bind(interpret_dict_add, _1, vm::Dictionary::SetMode::Add, true, 1)); + d.def_stack_word("b>idict! ", std::bind(interpret_dict_add, _1, vm::Dictionary::SetMode::Set, true, 1)); + d.def_stack_word("idict@ ", std::bind(interpret_dict_get, _1, 1, 3)); + d.def_stack_word("idict@- ", std::bind(interpret_dict_get, _1, 1, 7)); + d.def_stack_word("idict- ", std::bind(interpret_dict_get, _1, 1, 5)); d.def_stack_word("pfxdict!+ ", std::bind(interpret_pfx_dict_add, _1, vm::Dictionary::SetMode::Add, false)); d.def_stack_word("pfxdict! ", std::bind(interpret_pfx_dict_add, _1, vm::Dictionary::SetMode::Set, false)); d.def_stack_word("pfxdict@ ", interpret_pfx_dict_get); - d.def_ctx_word("dictmap ", interpret_dict_map); - d.def_ctx_word("dictmapext ", interpret_dict_map_ext); - d.def_ctx_word("dictforeach ", interpret_dict_foreach); + d.def_ctx_word("dictmap ", std::bind(interpret_dict_map, _1, false, false)); + d.def_ctx_word("dictmapext ", std::bind(interpret_dict_map, _1, true, false)); + d.def_ctx_word("idictmapext ", std::bind(interpret_dict_map, _1, true, true)); + d.def_ctx_word("dictforeach ", std::bind(interpret_dict_foreach, _1, false, false)); + d.def_ctx_word("idictforeach ", std::bind(interpret_dict_foreach, _1, false, true)); + d.def_ctx_word("dictforeachrev ", std::bind(interpret_dict_foreach, _1, true, false)); + d.def_ctx_word("idictforeachrev ", std::bind(interpret_dict_foreach, _1, true, true)); + d.def_ctx_word("dictforeachfromx ", std::bind(interpret_dict_foreach_from, _1, -1)); d.def_ctx_word("dictmerge ", interpret_dict_merge); d.def_ctx_word("dictdiff ", interpret_dict_diff); // slice/bitstring constants @@ -2756,6 +2888,10 @@ void init_words_common(Dictionary& d) { d.def_ctx_word("quit ", interpret_quit); d.def_ctx_word("bye ", interpret_bye); d.def_stack_word("halt ", interpret_halt); + // cmdline args + d.def_stack_word("$* ", std::bind(interpret_literal, _1, vm::StackEntry{cmdline_args})); + d.def_stack_word("$# ", interpret_get_cmdline_arg_count); + d.def_ctx_word("$() ", interpret_get_cmdline_arg); } void init_words_ton(Dictionary& d) { @@ -2768,34 +2904,34 @@ void init_words_ton(Dictionary& d) { d.def_stack_word("base64url>B ", std::bind(interpret_base64_to_bytes, _1, true, false)); } -void init_words_vm(Dictionary& d) { +void init_words_vm(Dictionary& d, bool enable_debug) { using namespace std::placeholders; - vm::init_op_cp0(); + vm::init_op_cp0(enable_debug); // vm run d.def_stack_word("vmlibs ", std::bind(interpret_literal, _1, vm::StackEntry{vm_libraries})); - d.def_ctx_word("runvmcode ", std::bind(interpret_run_vm_code, _1, false)); - d.def_ctx_word("gasrunvmcode ", std::bind(interpret_run_vm_code, _1, true)); - d.def_ctx_word("runvmdict ", std::bind(interpret_run_vm_dict, _1, false)); - d.def_ctx_word("gasrunvmdict ", std::bind(interpret_run_vm_dict, _1, true)); - d.def_ctx_word("runvm ", std::bind(interpret_run_vm, _1, false)); - d.def_ctx_word("gasrunvm ", std::bind(interpret_run_vm, _1, true)); - d.def_ctx_word("runvmctx ", std::bind(interpret_run_vm_c7, _1, false)); - d.def_ctx_word("gasrunvmctx ", std::bind(interpret_run_vm_c7, _1, true)); + // d.def_ctx_word("runvmcode ", std::bind(interpret_run_vm, _1, 0x40)); + // d.def_ctx_word("runvm ", std::bind(interpret_run_vm, _1, 0x45)); + d.def_ctx_word("runvmx ", std::bind(interpret_run_vm, _1, -1)); d.def_ctx_word("dbrunvm ", interpret_db_run_vm); d.def_ctx_word("dbrunvm-parallel ", interpret_db_run_vm_parallel); + d.def_stack_word("vmcont, ", interpret_store_vm_cont); + d.def_stack_word("vmcont@ ", interpret_fetch_vm_cont); } void import_cmdline_args(Dictionary& d, std::string arg0, int n, const char* const argv[]) { using namespace std::placeholders; LOG(DEBUG) << "import_cmdlist_args(" << arg0 << "," << n << ")"; d.def_stack_word("$0 ", std::bind(interpret_literal, _1, vm::StackEntry{arg0})); - for (int i = 0; i < n; i++) { - char buffer[14]; - sprintf(buffer, "$%d ", i + 1); - d.def_stack_word(buffer, std::bind(interpret_literal, _1, vm::StackEntry{argv[i]})); + vm::StackEntry list; + for (int i = n - 1; i >= 0; i--) { + list = vm::StackEntry::cons(vm::StackEntry{argv[i]}, list); + } + cmdline_args->set(std::move(list)); + for (int i = 1; i <= n; i++) { + char buffer[14]; + sprintf(buffer, "$%d ", i); + d.def_stack_word(buffer, std::bind(interpret_get_fixed_cmdline_arg, _1, i)); } - d.def_stack_word("$# ", std::bind(interpret_const, _1, n)); - d.def_ctx_word("$() ", interpret_get_cmdline_arg); } std::pair numeric_value_ext(std::string s, bool allow_frac = true) { diff --git a/submodules/ton/tonlib-src/crypto/fift/words.h b/submodules/ton/tonlib-src/crypto/fift/words.h index eac182e43b..de5b438930 100644 --- a/submodules/ton/tonlib-src/crypto/fift/words.h +++ b/submodules/ton/tonlib-src/crypto/fift/words.h @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once #include "Dictionary.h" @@ -33,7 +33,7 @@ struct Quit { struct SkipToEof {}; void init_words_common(Dictionary& dictionary); -void init_words_vm(Dictionary& dictionary); +void init_words_vm(Dictionary& dictionary, bool debug_enabled = false); void init_words_ton(Dictionary& dictionary); void import_cmdline_args(Dictionary& d, std::string arg0, int n, const char* const argv[]); diff --git a/submodules/ton/tonlib-src/crypto/func/abscode.cpp b/submodules/ton/tonlib-src/crypto/func/abscode.cpp index 8ff204f13c..8d73c80540 100644 --- a/submodules/ton/tonlib-src/crypto/func/abscode.cpp +++ b/submodules/ton/tonlib-src/crypto/func/abscode.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "func.h" @@ -138,7 +138,7 @@ void VarDescr::show(std::ostream& os, const char* name) const { } void VarDescr::set_const(long long value) { - return set_const(td::RefInt256{true, value}); + return set_const(td::make_refint(value)); } void VarDescr::set_const(td::RefInt256 value) { @@ -169,7 +169,7 @@ void VarDescr::set_const(td::RefInt256 value) { } void VarDescr::set_const_nan() { - set_const(td::RefInt256{true}); + set_const(td::make_refint()); } void VarDescr::operator|=(const VarDescr& y) { @@ -323,6 +323,20 @@ void Op::show(std::ostream& os, const std::vector& vars, std::string pfx show_var_list(os, right, vars); os << std::endl; break; + case _Tuple: + os << pfx << dis << "MKTUPLE "; + show_var_list(os, left, vars); + os << " := "; + show_var_list(os, right, vars); + os << std::endl; + break; + case _UnTuple: + os << pfx << dis << "UNTUPLE "; + show_var_list(os, left, vars); + os << " := "; + show_var_list(os, right, vars); + os << std::endl; + break; case _IntConst: os << pfx << dis << "CONST "; show_var_list(os, left, vars); @@ -343,6 +357,12 @@ void Op::show(std::ostream& os, const std::vector& vars, std::string pfx show_var_list(os, left, vars); os << " := " << (fun_ref ? fun_ref->name() : "(null)") << std::endl; break; + case _SetGlob: + os << pfx << dis << "SETGLOB "; + os << (fun_ref ? fun_ref->name() : "(null)") << " := "; + show_var_list(os, right, vars); + os << std::endl; + break; case _Repeat: os << pfx << dis << "REPEAT "; show_var_list(os, left, vars); diff --git a/submodules/ton/tonlib-src/crypto/func/analyzer.cpp b/submodules/ton/tonlib-src/crypto/func/analyzer.cpp index a80bc74e23..5af435bc8e 100644 --- a/submodules/ton/tonlib-src/crypto/func/analyzer.cpp +++ b/submodules/ton/tonlib-src/crypto/func/analyzer.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "func.h" @@ -29,6 +29,7 @@ namespace funC { void CodeBlob::simplify_var_types() { for (TmpVar& var : vars) { TypeExpr::remove_indirect(var.v_type); + var.v_type->recompute_width(); } } @@ -354,7 +355,9 @@ bool Op::compute_used_vars(const CodeBlob& code, bool edit) { case _IntConst: case _GlobVar: case _Call: - case _CallInd: { + case _CallInd: + case _Tuple: + case _UnTuple: { // left = EXEC right; if (!next_var_info.count_used(left) && is_pure()) { // all variables in `left` are not needed @@ -365,6 +368,13 @@ bool Op::compute_used_vars(const CodeBlob& code, bool edit) { } return std_compute_used_vars(); } + case _SetGlob: { + // GLOB = right + if (right.empty() && edit) { + disable(); + } + return std_compute_used_vars(right.empty()); + } case _Let: { // left = right std::size_t cnt = next_var_info.count_used(left); @@ -431,26 +441,25 @@ bool Op::compute_used_vars(const CodeBlob& code, bool edit) { } case _While: { // while (block0 || left) block1; - // ... { block0 left block1 } block0 left next - VarDescrList after_cond_first{next_var_info}; - after_cond_first += left; - code.compute_used_code_vars(block0, after_cond_first, false); - VarDescrList new_var_info{block0->var_info}; + // ... block0 left { block1 block0 left } next + VarDescrList new_var_info{next_var_info}; bool changes = false; do { - code.compute_used_code_vars(block1, block0->var_info, changes); - VarDescrList after_cond{block1->var_info}; + VarDescrList after_cond{new_var_info}; after_cond += left; code.compute_used_code_vars(block0, after_cond, changes); + code.compute_used_code_vars(block1, block0->var_info, changes); std::size_t n = new_var_info.size(); - new_var_info += block0->var_info; + new_var_info += block1->var_info; new_var_info.clear_last(); if (changes) { break; } changes = (new_var_info.size() == n); } while (changes <= edit); - return set_var_info(std::move(new_var_info)); + new_var_info += left; + code.compute_used_code_vars(block0, new_var_info, edit); + return set_var_info(block0->var_info); } case _Until: { // until (block0 || left); @@ -532,8 +541,11 @@ bool prune_unreachable(std::unique_ptr& ops) { switch (op.cl) { case Op::_IntConst: case Op::_GlobVar: + case Op::_SetGlob: case Op::_Call: case Op::_CallInd: + case Op::_Tuple: + case Op::_UnTuple: case Op::_Import: reach = true; break; @@ -695,7 +707,6 @@ VarDescrList Op::fwd_analyze(VarDescrList values) { values.add_newval(left[0]).set_const(int_const); break; } - case _GlobVar: case _Call: { prepare_args(values); auto func = dynamic_cast(fun_ref->value); @@ -718,12 +729,17 @@ VarDescrList Op::fwd_analyze(VarDescrList values) { } break; } + case _Tuple: + case _UnTuple: + case _GlobVar: case _CallInd: { for (var_idx_t i : left) { values.add_newval(i); } break; } + case _SetGlob: + break; case _Let: { std::vector old_val; assert(left.size() == right.size()); @@ -833,6 +849,9 @@ bool Op::mark_noreturn() { case _Import: case _IntConst: case _Let: + case _Tuple: + case _UnTuple: + case _SetGlob: case _GlobVar: case _CallInd: case _Call: diff --git a/submodules/ton/tonlib-src/crypto/func/asmops.cpp b/submodules/ton/tonlib-src/crypto/func/asmops.cpp index df4443a4d2..cb0fff1be1 100644 --- a/submodules/ton/tonlib-src/crypto/func/asmops.cpp +++ b/submodules/ton/tonlib-src/crypto/func/asmops.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "parser/srcread.h" #include "func.h" @@ -121,12 +121,49 @@ AsmOp AsmOp::BlkDrop(int a) { return AsmOp::Custom(os.str(), a, 0); } +AsmOp AsmOp::BlkDrop2(int a, int b) { + if (!b) { + return BlkDrop(a); + } + std::ostringstream os; + os << a << " " << b << " BLKDROP2"; + return AsmOp::Custom(os.str(), a + b, b); +} + AsmOp AsmOp::BlkReverse(int a, int b) { std::ostringstream os; os << a << " " << b << " REVERSE"; return AsmOp::Custom(os.str(), a + b, a + b); } +AsmOp AsmOp::Tuple(int a) { + switch (a) { + case 1: + return AsmOp::Custom("SINGLE", 1, 1); + case 2: + return AsmOp::Custom("PAIR", 2, 1); + case 3: + return AsmOp::Custom("TRIPLE", 3, 1); + } + std::ostringstream os; + os << a << " TUPLE"; + return AsmOp::Custom(os.str(), a, 1); +} + +AsmOp AsmOp::UnTuple(int a) { + switch (a) { + case 1: + return AsmOp::Custom("UNSINGLE", 1, 1); + case 2: + return AsmOp::Custom("UNPAIR", 1, 2); + case 3: + return AsmOp::Custom("UNTRIPLE", 1, 3); + } + std::ostringstream os; + os << a << " UNTUPLE"; + return AsmOp::Custom(os.str(), 1, a); +} + AsmOp AsmOp::IntConst(td::RefInt256 x) { if (x->signed_fits_bits(8)) { return AsmOp::Const(dec_string(std::move(x)) + " PUSHINT"); @@ -325,6 +362,8 @@ bool apply_op(StackTransform& trans, const AsmOp& op) { return trans.apply_pop(op.a); case AsmOp::a_const: return !op.a && op.b == 1 && trans.apply_push_newconst(); + case AsmOp::a_custom: + return op.is_gconst() && trans.apply_push_newconst(); default: return false; } diff --git a/submodules/ton/tonlib-src/crypto/func/builtins.cpp b/submodules/ton/tonlib-src/crypto/func/builtins.cpp index dd156f24c6..066da4602f 100644 --- a/submodules/ton/tonlib-src/crypto/func/builtins.cpp +++ b/submodules/ton/tonlib-src/crypto/func/builtins.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "func.h" @@ -27,8 +27,8 @@ using namespace std::literals::string_literals; * */ -int glob_func_cnt, undef_func_cnt; -std::vector glob_func; +int glob_func_cnt, undef_func_cnt, glob_var_cnt; +std::vector glob_func, glob_vars; SymDef* predefine_builtin_func(std::string name, TypeExpr* func_type) { sym_idx_t name_idx = sym::symbols.lookup(name, 1); @@ -44,30 +44,49 @@ SymDef* predefine_builtin_func(std::string name, TypeExpr* func_type) { } template -void define_builtin_func(std::string name, TypeExpr* func_type, const T& func, bool impure = false) { +SymDef* define_builtin_func(std::string name, TypeExpr* func_type, const T& func, bool impure = false) { SymDef* def = predefine_builtin_func(name, func_type); def->value = new SymValAsmFunc{func_type, func, impure}; + return def; } template -void define_builtin_func(std::string name, TypeExpr* func_type, const T& func, std::initializer_list arg_order, - std::initializer_list ret_order = {}, bool impure = false) { +SymDef* define_builtin_func(std::string name, TypeExpr* func_type, const T& func, std::initializer_list arg_order, + std::initializer_list ret_order = {}, bool impure = false) { SymDef* def = predefine_builtin_func(name, func_type); def->value = new SymValAsmFunc{func_type, func, arg_order, ret_order, impure}; + return def; } -void define_builtin_func(std::string name, TypeExpr* func_type, const AsmOp& macro, - std::initializer_list arg_order, std::initializer_list ret_order = {}, - bool impure = false) { +SymDef* define_builtin_func(std::string name, TypeExpr* func_type, const AsmOp& macro, + std::initializer_list arg_order, std::initializer_list ret_order = {}, + bool impure = false) { SymDef* def = predefine_builtin_func(name, func_type); def->value = new SymValAsmFunc{func_type, make_simple_compile(macro), arg_order, ret_order, impure}; + return def; } -bool SymValAsmFunc::compile(AsmOpList& dest, std::vector& in, std::vector& out) const { +SymDef* force_autoapply(SymDef* def) { + if (def) { + auto val = dynamic_cast(def->value); + if (val) { + val->auto_apply = true; + } + } + return def; +} + +template +SymDef* define_builtin_const(std::string name, TypeExpr* const_type, Args&&... args) { + return force_autoapply( + define_builtin_func(name, TypeExpr::new_map(TypeExpr::new_unit(), const_type), std::forward(args)...)); +} + +bool SymValAsmFunc::compile(AsmOpList& dest, std::vector& out, std::vector& in) const { if (simple_compile) { - return dest.append(simple_compile(in, out)); + return dest.append(simple_compile(out, in)); } else if (ext_compile) { - return ext_compile(dest, in, out); + return ext_compile(dest, out, in); } else { return false; } @@ -317,6 +336,12 @@ AsmOp exec_arg_op(std::string op, td::RefInt256 arg, int args, int retv) { return AsmOp::Custom(os.str(), args, retv); } +AsmOp exec_arg2_op(std::string op, long long imm1, long long imm2, int args, int retv) { + std::ostringstream os; + os << imm1 << ' ' << imm2 << ' ' << op; + return AsmOp::Custom(os.str(), args, retv); +} + AsmOp push_const(td::RefInt256 x) { return AsmOp::IntConst(std::move(x)); } @@ -603,7 +628,7 @@ AsmOp compile_mod(std::vector& res, std::vector& args, int r if ((*y.int_const == 1 || *y.int_const == -1) && x.always_finite()) { x.unused(); y.unused(); - r.set_const(td::RefInt256{true, 0}); + r.set_const(td::zero_refint()); return push_const(r.int_const); } int k = is_pos_pow2(y.int_const); @@ -740,7 +765,7 @@ AsmOp compile_cond_throw(std::vector& res, std::vector& args x.unused(); return skip_cond ? exec_arg_op("THROW", x.int_const, 0, 0) : exec_arg_op("THROW"s + suff, x.int_const, 1, 0); } else { - return skip_cond ? exec_op("THROWANY", 1, 0) : exec_arg_op("THROWANY"s + suff, 2, 0); + return skip_cond ? exec_op("THROWANY", 1, 0) : exec_op("THROWANY"s + suff, 2, 0); } } @@ -918,11 +943,11 @@ void define_builtins() { define_builtin_func("_<=_", arith_bin_op, std::bind(compile_cmp_int, _1, _2, 6)); define_builtin_func("_>=_", arith_bin_op, std::bind(compile_cmp_int, _1, _2, 3)); define_builtin_func("_<=>_", arith_bin_op, std::bind(compile_cmp_int, _1, _2, 7)); - define_builtin_func("true", Int, /* AsmOp::Const("TRUE") */ std::bind(compile_bool_const, _1, _2, true)); - define_builtin_func("false", Int, /* AsmOp::Const("FALSE") */ std::bind(compile_bool_const, _1, _2, false)); + define_builtin_const("true", Int, /* AsmOp::Const("TRUE") */ std::bind(compile_bool_const, _1, _2, true)); + define_builtin_const("false", Int, /* AsmOp::Const("FALSE") */ std::bind(compile_bool_const, _1, _2, false)); // define_builtin_func("null", Null, AsmOp::Const("PUSHNULL")); - define_builtin_func("nil", Tuple, AsmOp::Const("PUSHNULL")); - define_builtin_func("Nil", Tuple, AsmOp::Const("NIL")); + define_builtin_const("nil", Tuple, AsmOp::Const("PUSHNULL")); + define_builtin_const("Nil", Tuple, AsmOp::Const("NIL")); define_builtin_func("null?", TypeExpr::new_forall({X}, TypeExpr::new_map(X, Int)), compile_is_null); define_builtin_func("throw", impure_un_op, compile_throw, true); define_builtin_func("throw_if", impure_bin_op, std::bind(compile_cond_throw, _1, _2, true), true); @@ -949,7 +974,7 @@ void define_builtins() { define_builtin_func("~touch2", TypeExpr::new_forall({X, Y}, TypeExpr::new_map(XY, TypeExpr::new_tensor({XY, Unit}))), AsmOp::Nop()); define_builtin_func("~dump", TypeExpr::new_forall({X}, TypeExpr::new_map(X, TypeExpr::new_tensor({X, Unit}))), - AsmOp::Custom("s0 DUMP", 1, 1)); + AsmOp::Custom("s0 DUMP", 1, 1), true); define_builtin_func("run_method0", TypeExpr::new_map(Int, Unit), [](auto a, auto b, auto c) { return compile_run_method(a, b, c, 0, false); }, true); define_builtin_func("run_method1", TypeExpr::new_forall({X}, TypeExpr::new_map(TypeExpr::new_tensor({Int, X}), Unit)), diff --git a/submodules/ton/tonlib-src/crypto/func/codegen.cpp b/submodules/ton/tonlib-src/crypto/func/codegen.cpp index 70ae929df3..26d8215ea3 100644 --- a/submodules/ton/tonlib-src/crypto/func/codegen.cpp +++ b/submodules/ton/tonlib-src/crypto/func/codegen.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "func.h" @@ -84,7 +84,9 @@ void Stack::forget_const() { void Stack::issue_pop(int i) { validate(i); - o << AsmOp::Pop(i); + if (output_enabled()) { + o << AsmOp::Pop(i); + } at(i) = get(0); s.pop_back(); modified(); @@ -92,7 +94,9 @@ void Stack::issue_pop(int i) { void Stack::issue_push(int i) { validate(i); - o << AsmOp::Push(i); + if (output_enabled()) { + o << AsmOp::Push(i); + } s.push_back(get(i)); modified(); } @@ -101,7 +105,9 @@ void Stack::issue_xchg(int i, int j) { validate(i); validate(j); if (i != j && get(i) != get(j)) { - o << AsmOp::Xchg(i, j); + if (output_enabled()) { + o << AsmOp::Xchg(i, j); + } std::swap(at(i), at(j)); modified(); } @@ -183,6 +189,10 @@ void Stack::enforce_state(const StackLayout& req_stack) { if (i < depth() && s[i].first == x) { continue; } + while (depth() > 0 && std::find(req_stack.cbegin(), req_stack.cend(), get(0).first) == req_stack.cend()) { + // current TOS entry is unused in req_stack, drop it + issue_pop(0); + } int j = find(x); if (j >= depth() - i) { issue_push(j); @@ -292,27 +302,61 @@ bool Op::generate_code_step(Stack& stack) { } return true; } - case _GlobVar: { - assert(left.size() == 1); - auto p = next_var_info[left[0]]; - if (!p || p->is_unused() || disabled()) { + case _GlobVar: + if (dynamic_cast(fun_ref->value)) { + bool used = false; + for (auto i : left) { + auto p = next_var_info[i]; + if (p && !p->is_unused()) { + used = true; + } + } + if (!used || disabled()) { + return true; + } + std::string name = sym::symbols.get_name(fun_ref->sym_idx); + stack.o << AsmOp::Custom(name + " GETGLOB", 0, 1); + if (left.size() != 1) { + assert(left.size() <= 15); + stack.o << AsmOp::UnTuple((int)left.size()); + } + for (auto i : left) { + stack.push_new_var(i); + } + return true; + } else { + assert(left.size() == 1); + auto p = next_var_info[left[0]]; + if (!p || p->is_unused() || disabled()) { + return true; + } + stack.o << "CONT:<{"; + stack.o.indent(); + auto func = dynamic_cast(fun_ref->value); + if (func) { + // TODO: create and compile a true lambda instead of this (so that arg_order and ret_order would work correctly) + std::vector args0, res; + TypeExpr::remove_indirect(func->sym_type); + assert(func->get_type()->is_map()); + auto wr = func->get_type()->args.at(0)->get_width(); + auto wl = func->get_type()->args.at(1)->get_width(); + assert(wl >= 0 && wr >= 0); + for (int i = 0; i < wl; i++) { + res.emplace_back(0); + } + for (int i = 0; i < wr; i++) { + args0.emplace_back(0); + } + func->compile(stack.o, res, args0); // compile res := f (args0) + } else { + std::string name = sym::symbols.get_name(fun_ref->sym_idx); + stack.o << AsmOp::Custom(name + " CALLDICT", (int)right.size(), (int)left.size()); + } + stack.o.undent(); + stack.o << "}>"; + stack.push_new_var(left.at(0)); return true; } - auto func = dynamic_cast(fun_ref->value); - if (func) { - std::vector res; - res.reserve(left.size()); - for (var_idx_t i : left) { - res.emplace_back(i); - } - func->compile(stack.o, res, args); // compile res := f (args) - } else { - std::string name = sym::symbols.get_name(fun_ref->sym_idx); - stack.o << AsmOp::Custom(name + " CALLDICT", (int)right.size(), (int)left.size()); - } - stack.push_new_var(left[0]); - return true; - } case _Let: { assert(left.size() == right.size()); int i = 0; @@ -352,6 +396,32 @@ bool Op::generate_code_step(Stack& stack) { } return true; } + case _Tuple: + case _UnTuple: { + if (disabled()) { + return true; + } + std::vector last; + for (var_idx_t x : right) { + last.push_back(var_info[x] && var_info[x]->is_last()); + } + stack.rearrange_top(right, std::move(last)); + stack.opt_show(); + int k = (int)stack.depth() - (int)right.size(); + assert(k >= 0); + if (cl == _Tuple) { + stack.o << AsmOp::Tuple((int)right.size()); + assert(left.size() == 1); + } else { + stack.o << AsmOp::UnTuple((int)left.size()); + assert(right.size() == 1); + } + stack.s.resize(k); + for (int i = 0; i < (int)left.size(); i++) { + stack.push_new_var(left.at(i)); + } + return true; + } case _Call: case _CallInd: { if (disabled()) { @@ -395,7 +465,9 @@ bool Op::generate_code_step(Stack& stack) { assert(stack.s[k + i].first == right1[i]); } if (cl == _CallInd) { - stack.o << exec_arg_op("CALLARGS", (int)right.size() - 1, (int)right.size(), (int)left.size()); + // TODO: replace with exec_arg2_op() + stack.o << exec_arg2_op("CALLXARGS", (int)right.size() - 1, (int)left.size(), (int)right.size(), + (int)left.size()); } else { auto func = dynamic_cast(fun_ref->value); if (func) { @@ -420,6 +492,32 @@ bool Op::generate_code_step(Stack& stack) { } return true; } + case _SetGlob: { + assert(fun_ref && dynamic_cast(fun_ref->value)); + std::vector last; + for (var_idx_t x : right) { + last.push_back(var_info[x] && var_info[x]->is_last()); + } + stack.rearrange_top(right, std::move(last)); + stack.opt_show(); + int k = (int)stack.depth() - (int)right.size(); + assert(k >= 0); + for (int i = 0; i < (int)right.size(); i++) { + if (stack.s[k + i].first != right[i]) { + std::cerr << stack.o; + } + assert(stack.s[k + i].first == right[i]); + } + if (right.size() > 1) { + stack.o << AsmOp::Tuple((int)right.size()); + } + if (!right.empty()) { + std::string name = sym::symbols.get_name(fun_ref->sym_idx); + stack.o << AsmOp::Custom(name + " SETGLOB", 1, 0); + } + stack.s.resize(k); + return true; + } case _If: { if (block0->is_empty() && block1->is_empty()) { return true; @@ -448,7 +546,9 @@ bool Op::generate_code_step(Stack& stack) { } stack.o << "IF:<{"; stack.o.indent(); - Stack stack_copy{stack}; + Stack stack_copy{stack}, stack_target{stack}; + stack_target.disable_output(); + stack_target.drop_vars_except(next->var_info); block0->generate_code_all(stack_copy); stack_copy.drop_vars_except(var_info); stack_copy.opt_show(); @@ -457,7 +557,8 @@ bool Op::generate_code_step(Stack& stack) { stack.o << "}>"; return true; } - stack_copy.drop_vars_except(next->var_info); + // stack_copy.drop_vars_except(next->var_info); + stack_copy.enforce_state(stack_target.vars()); stack_copy.opt_show(); if (stack_copy.vars() == stack.vars()) { stack.o.undent(); @@ -487,7 +588,9 @@ bool Op::generate_code_step(Stack& stack) { } stack.o << "IFNOT:<{"; stack.o.indent(); - Stack stack_copy{stack}; + Stack stack_copy{stack}, stack_target{stack}; + stack_target.disable_output(); + stack_target.drop_vars_except(next->var_info); block1->generate_code_all(stack_copy); stack_copy.drop_vars_except(var_info); stack_copy.opt_show(); @@ -497,7 +600,8 @@ bool Op::generate_code_step(Stack& stack) { stack.merge_const(stack_copy); return true; } - stack_copy.drop_vars_except(next->var_info); + // stack_copy.drop_vars_except(next->var_info); + stack_copy.enforce_state(stack_target.vars()); stack_copy.opt_show(); if (stack_copy.vars() == stack.vars()) { stack.o.undent(); diff --git a/submodules/ton/tonlib-src/crypto/func/func.cpp b/submodules/ton/tonlib-src/crypto/func/func.cpp index 2b98c332bd..5b937c8331 100644 --- a/submodules/ton/tonlib-src/crypto/func/func.cpp +++ b/submodules/ton/tonlib-src/crypto/func/func.cpp @@ -130,6 +130,11 @@ int generate_output() { *outs << func_val->method_id << " DECLMETHOD " << name << "\n"; } } + for (SymDef* gvar_sym : glob_vars) { + assert(dynamic_cast(gvar_sym->value)); + std::string name = sym::symbols.get_name(gvar_sym->sym_idx); + *outs << std::string(indent * 2, ' ') << "DECLGLOBVAR " << name << "\n"; + } int errors = 0; for (SymDef* func_sym : glob_func) { try { diff --git a/submodules/ton/tonlib-src/crypto/func/func.h b/submodules/ton/tonlib-src/crypto/func/func.h index d1481299b8..fd2bffd63d 100644 --- a/submodules/ton/tonlib-src/crypto/func/func.h +++ b/submodules/ton/tonlib-src/crypto/func/func.h @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once #include @@ -36,7 +36,7 @@ namespace funC { extern int verbosity; extern bool op_rewrite_comments; -constexpr int optimize_depth = 12; +constexpr int optimize_depth = 20; enum Keyword { _Eof = -1, @@ -97,9 +97,11 @@ enum Keyword { _Forall, _Asm, _Impure, + _Global, _Extern, _Inline, _InlineRef, + _AutoApply, _MethodId, _Operator, _Infix, @@ -133,7 +135,7 @@ class IdSc { */ struct TypeExpr { - enum te_type { te_Unknown, te_Var, te_Indirect, te_Atomic, te_Tensor, te_Map, te_Type, te_ForAll } constr; + enum te_type { te_Unknown, te_Var, te_Indirect, te_Atomic, te_Tensor, te_Tuple, te_Map, te_Type, te_ForAll } constr; enum { _Int = Keyword::_Int, _Cell = Keyword::_Cell, @@ -159,6 +161,9 @@ struct TypeExpr { : constr(_constr), value((int)list.size()), args(std::move(list)) { compute_width(); } + TypeExpr(te_type _constr, TypeExpr* elem0) : constr(_constr), value(1), args{elem0} { + compute_width(); + } TypeExpr(te_type _constr, TypeExpr* elem0, std::vector list) : constr(_constr), value((int)list.size() + 1), args{elem0} { args.insert(args.end(), list.begin(), list.end()); @@ -181,6 +186,12 @@ struct TypeExpr { bool is_var() const { return constr == te_Var; } + bool is_map() const { + return constr == te_Map; + } + bool is_tuple() const { + return constr == te_Tuple; + } bool has_fixed_width() const { return minw == maxw; } @@ -222,6 +233,15 @@ struct TypeExpr { static TypeExpr* new_tensor(TypeExpr* te1, TypeExpr* te2, TypeExpr* te3) { return new_tensor({te1, te2, te3}); } + static TypeExpr* new_tuple(TypeExpr* arg0) { + return new TypeExpr{te_Tuple, arg0}; + } + static TypeExpr* new_tuple(std::vector list, bool red = false) { + return new_tuple(new_tensor(std::move(list), red)); + } + static TypeExpr* new_tuple(std::initializer_list list) { + return new_tuple(new_tensor(std::move(list))); + } static TypeExpr* new_var() { return new TypeExpr{te_Var, --type_vars, 1}; } @@ -498,8 +518,11 @@ struct Op { _Let, _IntConst, _GlobVar, + _SetGlob, _Import, _Return, + _Tuple, + _UnTuple, _If, _While, _Until, @@ -694,6 +717,7 @@ struct SymVal : sym::SymValBase { TypeExpr* sym_type; td::RefInt256 method_id; bool impure; + bool auto_apply{false}; short flags; // +1 = inline, +2 = inline_ref SymVal(int _type, int _idx, TypeExpr* _stype = nullptr, bool _impure = false) : sym::SymValBase(_type, _idx), sym_type(_stype), impure(_impure), flags(0) { @@ -745,8 +769,20 @@ struct SymValType : sym::SymValBase { } }; -extern int glob_func_cnt, undef_func_cnt; -extern std::vector glob_func; +struct SymValGlobVar : sym::SymValBase { + TypeExpr* sym_type; + int out_idx{0}; + SymValGlobVar(int val, TypeExpr* gvtype, int oidx = 0) + : sym::SymValBase(_GlobVar, val), sym_type(gvtype), out_idx(oidx) { + } + ~SymValGlobVar() override = default; + TypeExpr* get_type() const { + return sym_type; + } +}; + +extern int glob_func_cnt, undef_func_cnt, glob_var_cnt; +extern std::vector glob_func, glob_vars; /* * @@ -771,10 +807,12 @@ struct Expr { _Apply, _VarApply, _TypeApply, - _Tuple, + _MkTuple, + _Tensor, _Const, _Var, _Glob, + _GlobVar, _Letop, _LetFirst, _Hole, @@ -824,6 +862,12 @@ struct Expr { bool is_type() const { return flags & _IsType; } + bool is_type_apply() const { + return cls == _TypeApply; + } + bool is_mktuple() const { + return cls == _MkTuple; + } void chk_rvalue(const Lexem& lem) const; void chk_lvalue(const Lexem& lem) const; void chk_type(const Lexem& lem) const; @@ -836,7 +880,8 @@ struct Expr { } int define_new_vars(CodeBlob& code); int predefine_vars(); - std::vector pre_compile(CodeBlob& code) const; + std::vector pre_compile(CodeBlob& code, bool lval = false) const; + static std::vector pre_compile_let(CodeBlob& code, Expr* lhs, Expr* rhs, const SrcLocation& here); var_idx_t new_tmp(CodeBlob& code) const; std::vector new_tmp_vect(CodeBlob& code) const { return {new_tmp(code)}; @@ -860,6 +905,7 @@ struct AsmOp { int t{a_none}; int indent{0}; int a, b, c; + bool gconst{false}; std::string op; struct SReg { int idx; @@ -878,6 +924,7 @@ struct AsmOp { AsmOp(int _t, int _a, int _b) : t(_t), a(_a), b(_b) { } AsmOp(int _t, int _a, int _b, std::string _op) : t(_t), a(_a), b(_b), op(std::move(_op)) { + compute_gconst(); } AsmOp(int _t, int _a, int _b, int _c) : t(_t), a(_a), b(_b), c(_c) { } @@ -886,6 +933,9 @@ struct AsmOp { void out(std::ostream& os) const; void out_indent_nl(std::ostream& os, bool no_nl = false) const; std::string to_string() const; + void compute_gconst() { + gconst = (is_custom() && (op == "PUSHNULL" || op == "NEWC" || op == "NEWB" || op == "TRUE" || op == "FALSE")); + } bool is_nop() const { return t == a_none && op.empty(); } @@ -925,6 +975,9 @@ struct AsmOp { *y = b; return is_xchg(); } + bool is_xchg_short() const { + return is_xchg() && (a <= 1 || b <= 1); + } bool is_swap() const { return is_xchg(0, 1); } @@ -932,7 +985,7 @@ struct AsmOp { return t == a_const && !a && b == 1; } bool is_gconst() const { - return (t == a_const || t == a_custom) && !a && b == 1; + return !a && b == 1 && (t == a_const || gconst); } static AsmOp Nop() { return AsmOp(a_none); @@ -985,6 +1038,7 @@ struct AsmOp { static AsmOp BlkSwap(int a, int b); static AsmOp BlkPush(int a, int b); static AsmOp BlkDrop(int a); + static AsmOp BlkDrop2(int a, int b); static AsmOp BlkReverse(int a, int b); static AsmOp make_stk2(int a, int b, const char* str, int delta); static AsmOp make_stk3(int a, int b, int c, const char* str, int delta); @@ -1005,6 +1059,8 @@ struct AsmOp { return AsmOp(a_custom, args, retv, custom_op); } static AsmOp Parse(std::string custom_op, int args, int retv = 1); + static AsmOp Tuple(int a); + static AsmOp UnTuple(int a); }; inline std::ostream& operator<<(std::ostream& os, const AsmOp& op) { @@ -1155,6 +1211,7 @@ struct StackTransform { bool apply_push(int i); bool apply_pop(int i = 0); bool apply_push_newconst(); + bool apply_blkpop(int k); bool apply(const StackTransform& other); // this = this * other bool preapply(const StackTransform& other); // this = other * this // c := a * b @@ -1211,12 +1268,22 @@ struct StackTransform { } bool is_xchg(int i, int j) const; bool is_xchg(int* i, int* j) const; + bool is_xchg_xchg(int i, int j, int k, int l) const; + bool is_xchg_xchg(int* i, int* j, int* k, int* l) const; bool is_push(int i) const; bool is_push(int* i) const; bool is_pop(int i) const; bool is_pop(int* i) const; + bool is_pop_pop(int i, int j) const; + bool is_pop_pop(int* i, int* j) const; bool is_rot() const; bool is_rotrev() const; + bool is_push_rot(int i) const; + bool is_push_rot(int* i) const; + bool is_push_rotrev(int i) const; + bool is_push_rotrev(int* i) const; + bool is_push_xchg(int i, int j, int k) const; + bool is_push_xchg(int* i, int* j, int* k) const; bool is_xchg2(int i, int j) const; bool is_xchg2(int* i, int* j) const; bool is_xcpu(int i, int j) const; @@ -1241,11 +1308,23 @@ struct StackTransform { bool is_blkpush(int i, int j) const; bool is_blkpush(int* i, int* j) const; bool is_blkdrop(int* i) const; + bool is_blkdrop2(int i, int j) const; + bool is_blkdrop2(int* i, int* j) const; bool is_reverse(int i, int j) const; bool is_reverse(int* i, int* j) const; bool is_nip_seq(int i, int j = 0) const; bool is_nip_seq(int* i) const; bool is_nip_seq(int* i, int* j) const; + bool is_pop_blkdrop(int i, int k) const; + bool is_pop_blkdrop(int* i, int* k) const; + bool is_2pop_blkdrop(int i, int j, int k) const; + bool is_2pop_blkdrop(int* i, int* j, int* k) const; + bool is_const_rot(int c) const; + bool is_const_rot(int* c) const; + bool is_const_pop(int c, int i) const; + bool is_const_pop(int* c, int* i) const; + bool is_push_const(int i, int c) const; + bool is_push_const(int* i, int* c) const; void show(std::ostream& os, int mode = 0) const; @@ -1282,11 +1361,12 @@ struct Optimizer { AsmOpCons* op_cons_[n]; int offs_[n]; StackTransform tr_[n]; + int mode_{0}; Optimizer() { } - Optimizer(bool debug) : debug_(debug) { + Optimizer(bool debug, int mode = 0) : debug_(debug), mode_(mode) { } - Optimizer(AsmOpConsList code, bool debug = false) : Optimizer(debug) { + Optimizer(AsmOpConsList code, bool debug = false, int mode = 0) : Optimizer(debug, mode) { set_code(std::move(code)); } void set_code(AsmOpConsList code_); @@ -1302,19 +1382,28 @@ struct Optimizer { void show_head() const; void show_left() const; void show_right() const; - bool is_const_push_swap() const; - bool rewrite_const_push_swap(); + bool find_const_op(int* op_idx, int cst); + bool is_push_const(int* i, int* c) const; + bool rewrite_push_const(int i, int c); bool is_const_push_xchgs(); bool rewrite_const_push_xchgs(); - bool simple_rewrite(int p, AsmOp&& new_op); - bool simple_rewrite(int p, AsmOp&& new_op1, AsmOp&& new_op2); - bool simple_rewrite(AsmOp&& new_op) { - return simple_rewrite(p_, std::move(new_op)); + bool is_const_rot(int* c) const; + bool rewrite_const_rot(int c); + bool is_const_pop(int* c, int* i) const; + bool rewrite_const_pop(int c, int i); + bool rewrite(int p, AsmOp&& new_op); + bool rewrite(int p, AsmOp&& new_op1, AsmOp&& new_op2); + bool rewrite(int p, AsmOp&& new_op1, AsmOp&& new_op2, AsmOp&& new_op3); + bool rewrite(AsmOp&& new_op) { + return rewrite(p_, std::move(new_op)); } - bool simple_rewrite(AsmOp&& new_op1, AsmOp&& new_op2) { - return simple_rewrite(p_, std::move(new_op1), std::move(new_op2)); + bool rewrite(AsmOp&& new_op1, AsmOp&& new_op2) { + return rewrite(p_, std::move(new_op1), std::move(new_op2)); } - bool simple_rewrite_nop(); + bool rewrite(AsmOp&& new_op1, AsmOp&& new_op2, AsmOp&& new_op3) { + return rewrite(p_, std::move(new_op1), std::move(new_op2), std::move(new_op3)); + } + bool rewrite_nop(); bool is_pred(const std::function& pred, int min_p = 2); bool is_same_as(const StackTransform& trans, int min_p = 2); bool is_rot(); @@ -1325,9 +1414,14 @@ struct Optimizer { bool is_2swap(); bool is_2over(); bool is_xchg(int* i, int* j); + bool is_xchg_xchg(int* i, int* j, int* k, int* l); bool is_push(int* i); bool is_pop(int* i); + bool is_pop_pop(int* i, int* j); bool is_nop(); + bool is_push_rot(int* i); + bool is_push_rotrev(int* i); + bool is_push_xchg(int* i, int* j, int* k); bool is_xchg2(int* i, int* j); bool is_xcpu(int* i, int* j); bool is_puxc(int* i, int* j); @@ -1343,19 +1437,22 @@ struct Optimizer { bool is_blkswap(int* i, int* j); bool is_blkpush(int* i, int* j); bool is_blkdrop(int* i); + bool is_blkdrop2(int* i, int* j); bool is_reverse(int* i, int* j); bool is_nip_seq(int* i, int* j); + bool is_pop_blkdrop(int* i, int* k); + bool is_2pop_blkdrop(int* i, int* j, int* k); AsmOpConsList extract_code(); }; -AsmOpConsList optimize_code_head(AsmOpConsList op_list); -AsmOpConsList optimize_code(AsmOpConsList op_list); +AsmOpConsList optimize_code_head(AsmOpConsList op_list, int mode = 0); +AsmOpConsList optimize_code(AsmOpConsList op_list, int mode); void optimize_code(AsmOpList& ops); struct Stack { StackLayoutExt s; AsmOpList& o; - enum { _StkCmt = 1, _CptStkCmt = 2, _DisableOpt = 4, _Shown = 256, _Garbage = -0x10000 }; + enum { _StkCmt = 1, _CptStkCmt = 2, _DisableOpt = 4, _DisableOut = 128, _Shown = 256, _Garbage = -0x10000 }; int mode; Stack(AsmOpList& _o, int _mode = 0) : o(_o), mode(_mode) { } @@ -1381,6 +1478,15 @@ struct Stack { var_const_idx_t get(int i) const { return at(i); } + bool output_disabled() const { + return mode & _DisableOut; + } + bool output_enabled() const { + return !output_disabled(); + } + void disable_output() { + mode |= _DisableOut; + } StackLayout vars() const; int find(var_idx_t var, int from = 0) const; int find(var_idx_t var, int from, int to) const; @@ -1470,7 +1576,7 @@ struct SymValAsmFunc : SymValFunc { std::initializer_list ret_order = {}, bool impure = false) : SymValFunc(-1, ft, arg_order, ret_order, impure), ext_compile(std::move(_compile)) { } - bool compile(AsmOpList& dest, std::vector& in, std::vector& out) const; + bool compile(AsmOpList& dest, std::vector& out, std::vector& in) const; }; // defined in builtins.cpp @@ -1478,6 +1584,7 @@ AsmOp exec_arg_op(std::string op, long long arg); AsmOp exec_arg_op(std::string op, long long arg, int args, int retv = 1); AsmOp exec_arg_op(std::string op, td::RefInt256 arg); AsmOp exec_arg_op(std::string op, td::RefInt256 arg, int args, int retv = 1); +AsmOp exec_arg2_op(std::string op, long long imm1, long long imm2, int args, int retv = 1); AsmOp push_const(td::RefInt256 x); void define_builtins(); diff --git a/submodules/ton/tonlib-src/crypto/func/gen-abscode.cpp b/submodules/ton/tonlib-src/crypto/func/gen-abscode.cpp index a3cc52042d..c0a8985a64 100644 --- a/submodules/ton/tonlib-src/crypto/func/gen-abscode.cpp +++ b/submodules/ton/tonlib-src/crypto/func/gen-abscode.cpp @@ -14,10 +14,12 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "func.h" +using namespace std::literals::string_literals; + namespace funC { /* @@ -164,7 +166,8 @@ bool Expr::deduce_type(const Lexem& lem) { int Expr::define_new_vars(CodeBlob& code) { switch (cls) { - case _Tuple: + case _Tensor: + case _MkTuple: case _TypeApply: { int res = 0; for (const auto& x : args) { @@ -189,7 +192,8 @@ int Expr::define_new_vars(CodeBlob& code) { int Expr::predefine_vars() { switch (cls) { - case _Tuple: + case _Tensor: + case _MkTuple: case _TypeApply: { int res = 0; for (const auto& x : args) { @@ -201,6 +205,7 @@ int Expr::predefine_vars() { if (!sym) { assert(val < 0 && here.defined()); sym = sym::define_symbol(~val, false, here); + // std::cerr << "predefining variable " << sym::symbols.get_name(~val) << std::endl; if (!sym) { throw src::ParseError{here, std::string{"redefined variable `"} + sym::symbols.get_name(~val) + "`"}; } @@ -216,12 +221,51 @@ var_idx_t Expr::new_tmp(CodeBlob& code) const { return code.create_tmp_var(e_type, &here); } -std::vector Expr::pre_compile(CodeBlob& code) const { +std::vector Expr::pre_compile_let(CodeBlob& code, Expr* lhs, Expr* rhs, const SrcLocation& here) { + while (lhs->is_type_apply()) { + lhs = lhs->args.at(0); + } + while (rhs->is_type_apply()) { + rhs = rhs->args.at(0); + } + if (lhs->is_mktuple()) { + if (rhs->is_mktuple()) { + return pre_compile_let(code, lhs->args.at(0), rhs->args.at(0), here); + } + auto right = rhs->pre_compile(code); + TypeExpr::remove_indirect(rhs->e_type); + auto unpacked_type = rhs->e_type->args.at(0); + std::vector tmp{code.create_tmp_var(unpacked_type, &rhs->here)}; + code.emplace_back(lhs->here, Op::_UnTuple, tmp, std::move(right)); + auto tvar = new Expr{_Var}; + tvar->set_val(tmp[0]); + tvar->set_location(rhs->here); + tvar->e_type = unpacked_type; + pre_compile_let(code, lhs->args.at(0), tvar, here); + return tmp; + } + auto right = rhs->pre_compile(code); + if (lhs->cls == Expr::_GlobVar) { + assert(lhs->sym); + auto& op = code.emplace_back(here, Op::_SetGlob, std::vector{}, right, lhs->sym); + op.flags |= Op::_Impure; + } else { + auto left = lhs->pre_compile(code, true); + code.emplace_back(here, Op::_Let, std::move(left), right); + } + return right; +} + +std::vector Expr::pre_compile(CodeBlob& code, bool lval) const { + if (lval && !(cls == _Tensor || cls == _Var || cls == _Hole || cls == _TypeApply)) { + std::cerr << "lvalue expression constructor is " << cls << std::endl; + throw src::Fatal{"cannot compile lvalue expression with unknown constructor"}; + } switch (cls) { - case _Tuple: { + case _Tensor: { std::vector res; for (const auto& x : args) { - auto add = x->pre_compile(code); + auto add = x->pre_compile(code, lval); res.insert(res.end(), add.cbegin(), add.cend()); } return res; @@ -253,7 +297,7 @@ std::vector Expr::pre_compile(CodeBlob& code) const { return rvect; } case _TypeApply: - return args[0]->pre_compile(code); + return args[0]->pre_compile(code, lval); case _Var: case _Hole: return {val}; @@ -282,25 +326,29 @@ std::vector Expr::pre_compile(CodeBlob& code) const { code.emplace_back(here, Op::_IntConst, rvect, intval); return rvect; } - case _Glob: { + case _Glob: + case _GlobVar: { auto rvect = new_tmp_vect(code); code.emplace_back(here, Op::_GlobVar, rvect, std::vector{}, sym); return rvect; } case _Letop: { - auto right = args[1]->pre_compile(code); - auto left = args[0]->pre_compile(code); - code.emplace_back(here, Op::_Let, std::move(left), right); - return right; + return pre_compile_let(code, args.at(0), args.at(1), here); } case _LetFirst: { auto rvect = new_tmp_vect(code); auto right = args[1]->pre_compile(code); - auto left = args[0]->pre_compile(code); + auto left = args[0]->pre_compile(code, true); left.push_back(rvect[0]); code.emplace_back(here, Op::_Let, std::move(left), std::move(right)); return rvect; } + case _MkTuple: { + auto left = new_tmp_vect(code); + auto right = args[0]->pre_compile(code); + code.emplace_back(here, Op::_Tuple, left, std::move(right)); + return left; + } case _CondExpr: { auto cond = args[0]->pre_compile(code); assert(cond.size() == 1); diff --git a/submodules/ton/tonlib-src/crypto/func/keywords.cpp b/submodules/ton/tonlib-src/crypto/func/keywords.cpp index c640f4fe71..47975e7fec 100644 --- a/submodules/ton/tonlib-src/crypto/func/keywords.cpp +++ b/submodules/ton/tonlib-src/crypto/func/keywords.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "func.h" @@ -46,6 +46,8 @@ void define_keywords() { .add_kw_char(';') .add_kw_char('(') .add_kw_char(')') + .add_kw_char('[') + .add_kw_char(']') .add_kw_char('{') .add_kw_char('}') .add_kw_char('=') @@ -113,10 +115,12 @@ void define_keywords() { .add_keyword("forall", Kw::_Forall); sym::symbols.add_keyword("extern", Kw::_Extern) + .add_keyword("global", Kw::_Global) .add_keyword("asm", Kw::_Asm) .add_keyword("impure", Kw::_Impure) .add_keyword("inline", Kw::_Inline) .add_keyword("inline_ref", Kw::_InlineRef) + .add_keyword("auto_apply", Kw::_AutoApply) .add_keyword("method_id", Kw::_MethodId) .add_keyword("operator", Kw::_Operator) .add_keyword("infix", Kw::_Infix) diff --git a/submodules/ton/tonlib-src/crypto/func/optimize.cpp b/submodules/ton/tonlib-src/crypto/func/optimize.cpp index 95b4403c46..85c1fdd300 100644 --- a/submodules/ton/tonlib-src/crypto/func/optimize.cpp +++ b/submodules/ton/tonlib-src/crypto/func/optimize.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "func.h" @@ -134,18 +134,70 @@ bool Optimizer::say(std::string str) const { return true; } -bool Optimizer::is_const_push_swap() const { - return l_ >= 3 && op_[0]->is_gconst() && op_[1]->is_push() && op_[1]->a >= 1 && op_[2]->is_swap(); +bool Optimizer::find_const_op(int* op_idx, int cst) { + for (int i = 0; i < l2_; i++) { + if (op_[i]->is_gconst() && tr_[i].get(0) == cst) { + *op_idx = i; + return true; + } + } + return false; +} + +bool Optimizer::is_push_const(int* i, int* c) const { + return pb_ >= 3 && pb_ <= l2_ && tr_[pb_ - 1].is_push_const(i, c); } // PUSHCONST c ; PUSH s(i+1) ; SWAP -> PUSH s(i) ; PUSHCONST c -bool Optimizer::rewrite_const_push_swap() { - p_ = 3; +bool Optimizer::rewrite_push_const(int i, int c) { + p_ = pb_; q_ = 2; + int idx = -1; + if (!(p_ >= 2 && find_const_op(&idx, c) && idx < p_)) { + return false; + } show_left(); - oq_[1] = std::move(op_[0]); - oq_[0] = std::move(op_[1]); - (oq_[0]->a)--; + oq_[1] = std::move(op_[idx]); + oq_[0] = std::move(op_[!idx]); + *oq_[0] = AsmOp::Push(i); + show_right(); + return true; +} + +bool Optimizer::is_const_rot(int* c) const { + return pb_ >= 3 && pb_ <= l2_ && tr_[pb_ - 1].is_const_rot(c); +} + +bool Optimizer::rewrite_const_rot(int c) { + p_ = pb_; + q_ = 2; + int idx = -1; + if (!(p_ >= 2 && find_const_op(&idx, c) && idx < p_)) { + return false; + } + show_left(); + oq_[0] = std::move(op_[idx]); + oq_[1] = std::move(op_[!idx]); + *oq_[1] = AsmOp::Custom("ROT", 3, 3); + show_right(); + return true; +} + +bool Optimizer::is_const_pop(int* c, int* i) const { + return pb_ >= 3 && pb_ <= l2_ && tr_[pb_ - 1].is_const_pop(c, i); +} + +bool Optimizer::rewrite_const_pop(int c, int i) { + p_ = pb_; + q_ = 2; + int idx = -1; + if (!(p_ >= 2 && find_const_op(&idx, c) && idx < p_)) { + return false; + } + show_left(); + oq_[0] = std::move(op_[idx]); + oq_[1] = std::move(op_[!idx]); + *oq_[1] = AsmOp::Pop(i); show_right(); return true; } @@ -236,7 +288,7 @@ bool Optimizer::rewrite_const_push_xchgs() { return true; } -bool Optimizer::simple_rewrite(int p, AsmOp&& new_op) { +bool Optimizer::rewrite(int p, AsmOp&& new_op) { assert(p > 0 && p <= l_); p_ = p; q_ = 1; @@ -247,7 +299,7 @@ bool Optimizer::simple_rewrite(int p, AsmOp&& new_op) { return true; } -bool Optimizer::simple_rewrite(int p, AsmOp&& new_op1, AsmOp&& new_op2) { +bool Optimizer::rewrite(int p, AsmOp&& new_op1, AsmOp&& new_op2) { assert(p > 1 && p <= l_); p_ = p; q_ = 2; @@ -260,7 +312,22 @@ bool Optimizer::simple_rewrite(int p, AsmOp&& new_op1, AsmOp&& new_op2) { return true; } -bool Optimizer::simple_rewrite_nop() { +bool Optimizer::rewrite(int p, AsmOp&& new_op1, AsmOp&& new_op2, AsmOp&& new_op3) { + assert(p > 2 && p <= l_); + p_ = p; + q_ = 3; + show_left(); + oq_[0] = std::move(op_[0]); + *oq_[0] = new_op1; + oq_[1] = std::move(op_[1]); + *oq_[1] = new_op2; + oq_[2] = std::move(op_[2]); + *oq_[2] = new_op3; + show_right(); + return true; +} + +bool Optimizer::rewrite_nop() { assert(p_ > 0 && p_ <= l_); q_ = 0; show_left(); @@ -326,6 +393,13 @@ bool Optimizer::is_xchg(int* i, int* j) { return is_pred([i, j](const auto& t) { return t.is_xchg(i, j) && ((*i < 16 && *j < 16) || (!*i && *j < 256)); }); } +bool Optimizer::is_xchg_xchg(int* i, int* j, int* k, int* l) { + return is_pred([i, j, k, l](const auto& t) { + return t.is_xchg_xchg(i, j, k, l) && (*i < 2 && *j < (*i ? 16 : 256) && *k < 2 && *l < (*k ? 16 : 256)); + }) && + (!(p_ == 2 && op_[0]->is_xchg(*i, *j) && op_[1]->is_xchg(*k, *l))); +} + bool Optimizer::is_push(int* i) { return is_pred([i](const auto& t) { return t.is_push(i) && *i < 256; }); } @@ -334,6 +408,23 @@ bool Optimizer::is_pop(int* i) { return is_pred([i](const auto& t) { return t.is_pop(i) && *i < 256; }); } +bool Optimizer::is_pop_pop(int* i, int* j) { + return is_pred([i, j](const auto& t) { return t.is_pop_pop(i, j) && *i < 256 && *j < 256; }, 3); +} + +bool Optimizer::is_push_rot(int* i) { + return is_pred([i](const auto& t) { return t.is_push_rot(i) && *i < 16; }, 3); +} + +bool Optimizer::is_push_rotrev(int* i) { + return is_pred([i](const auto& t) { return t.is_push_rotrev(i) && *i < 16; }, 3); +} + +bool Optimizer::is_push_xchg(int* i, int* j, int* k) { + return is_pred([i, j, k](const auto& t) { return t.is_push_xchg(i, j, k) && *i < 16 && *j < 16 && *k < 16; }) && + !(p_ == 2 && op_[0]->is_push() && op_[1]->is_xchg()); +} + bool Optimizer::is_xchg2(int* i, int* j) { return is_pred([i, j](const auto& t) { return t.is_xchg2(i, j) && *i < 16 && *j < 16; }); } @@ -367,7 +458,8 @@ bool Optimizer::is_xcpu2(int* i, int* j, int* k) { } bool Optimizer::is_puxc2(int* i, int* j, int* k) { - return is_pred([i, j, k](const auto& t) { return t.is_puxc2(i, j, k) && *i < 16 && *j < 15 && *k < 15; }); + return is_pred( + [i, j, k](const auto& t) { return t.is_puxc2(i, j, k) && *i < 16 && *j < 15 && *k < 15 && *j + *k != -1; }); } bool Optimizer::is_puxcpu(int* i, int* j, int* k) { @@ -394,6 +486,10 @@ bool Optimizer::is_blkdrop(int* i) { return is_pred([i](const auto& t) { return t.is_blkdrop(i) && *i > 0 && *i < 16; }); } +bool Optimizer::is_blkdrop2(int* i, int* j) { + return is_pred([i, j](const auto& t) { return t.is_blkdrop2(i, j) && *i > 0 && *i < 16 && *j > 0 && *j < 16; }); +} + bool Optimizer::is_reverse(int* i, int* j) { return is_pred([i, j](const auto& t) { return t.is_reverse(i, j) && *i >= 2 && *i <= 17 && *j < 16; }); } @@ -402,6 +498,16 @@ bool Optimizer::is_nip_seq(int* i, int* j) { return is_pred([i, j](const auto& t) { return t.is_nip_seq(i, j) && *i >= 3 && *i <= 15; }); } +bool Optimizer::is_pop_blkdrop(int* i, int* k) { + return is_pred([i, k](const auto& t) { return t.is_pop_blkdrop(i, k) && *i >= *k && *k >= 2 && *k <= 15; }, 3); +} + +bool Optimizer::is_2pop_blkdrop(int* i, int* j, int* k) { + return is_pred( + [i, j, k](const auto& t) { return t.is_2pop_blkdrop(i, j, k) && *i >= *k && *j >= *k && *k >= 2 && *k <= 15; }, + 3); +} + bool Optimizer::compute_stack_transforms() { StackTransform trans; for (int i = 0; i < l_; i++) { @@ -448,34 +554,41 @@ bool Optimizer::find_at_least(int pb) { p_ = q_ = 0; pb_ = pb; // show_stack_transforms(); - int i = -100, j = -100, k = -100; - return (is_const_push_swap() && 3 >= pb && rewrite_const_push_swap()) || (is_nop() && simple_rewrite_nop()) || - (is_const_push_xchgs() && rewrite_const_push_xchgs()) || - (is_xchg(&i, &j) && simple_rewrite(AsmOp::Xchg(i, j))) || (is_push(&i) && simple_rewrite(AsmOp::Push(i))) || - (is_pop(&i) && simple_rewrite(AsmOp::Pop(i))) || (is_rot() && simple_rewrite(AsmOp::Custom("ROT", 3, 3))) || - (is_rotrev() && simple_rewrite(AsmOp::Custom("-ROT", 3, 3))) || - (is_2dup() && simple_rewrite(AsmOp::Custom("2DUP", 2, 4))) || - (is_2swap() && simple_rewrite(AsmOp::Custom("2SWAP", 2, 4))) || - (is_2over() && simple_rewrite(AsmOp::Custom("2OVER", 2, 4))) || - (is_tuck() && simple_rewrite(AsmOp::Custom("TUCK", 2, 3))) || - (is_2drop() && simple_rewrite(AsmOp::Custom("2DROP", 2, 0))) || - (is_xchg2(&i, &j) && simple_rewrite(AsmOp::Xchg2(i, j))) || - (is_xcpu(&i, &j) && simple_rewrite(AsmOp::XcPu(i, j))) || - (is_puxc(&i, &j) && simple_rewrite(AsmOp::PuXc(i, j))) || - (is_push2(&i, &j) && simple_rewrite(AsmOp::Push2(i, j))) || - (is_blkswap(&i, &j) && simple_rewrite(AsmOp::BlkSwap(i, j))) || - (is_blkpush(&i, &j) && simple_rewrite(AsmOp::BlkPush(i, j))) || - (is_blkdrop(&i) && simple_rewrite(AsmOp::BlkDrop(i))) || - (is_reverse(&i, &j) && simple_rewrite(AsmOp::BlkReverse(i, j))) || - (is_nip_seq(&i, &j) && simple_rewrite(AsmOp::Xchg(i, j), AsmOp::BlkDrop(i))) || - (is_xchg3(&i, &j, &k) && simple_rewrite(AsmOp::Xchg3(i, j, k))) || - (is_xc2pu(&i, &j, &k) && simple_rewrite(AsmOp::Xc2Pu(i, j, k))) || - (is_xcpuxc(&i, &j, &k) && simple_rewrite(AsmOp::XcPuXc(i, j, k))) || - (is_xcpu2(&i, &j, &k) && simple_rewrite(AsmOp::XcPu2(i, j, k))) || - (is_puxc2(&i, &j, &k) && simple_rewrite(AsmOp::PuXc2(i, j, k))) || - (is_puxcpu(&i, &j, &k) && simple_rewrite(AsmOp::PuXcPu(i, j, k))) || - (is_pu2xc(&i, &j, &k) && simple_rewrite(AsmOp::Pu2Xc(i, j, k))) || - (is_push3(&i, &j, &k) && simple_rewrite(AsmOp::Push3(i, j, k))); + int i, j, k, l, c; + return (is_push_const(&i, &c) && rewrite_push_const(i, c)) || (is_nop() && rewrite_nop()) || + (!(mode_ & 1) && is_const_rot(&c) && rewrite_const_rot(c)) || + (is_const_push_xchgs() && rewrite_const_push_xchgs()) || (is_const_pop(&c, &i) && rewrite_const_pop(c, i)) || + (is_xchg(&i, &j) && rewrite(AsmOp::Xchg(i, j))) || (is_push(&i) && rewrite(AsmOp::Push(i))) || + (is_pop(&i) && rewrite(AsmOp::Pop(i))) || (is_pop_pop(&i, &j) && rewrite(AsmOp::Pop(i), AsmOp::Pop(j))) || + (is_xchg_xchg(&i, &j, &k, &l) && rewrite(AsmOp::Xchg(i, j), AsmOp::Xchg(k, l))) || + (!(mode_ & 1) && + ((is_rot() && rewrite(AsmOp::Custom("ROT", 3, 3))) || (is_rotrev() && rewrite(AsmOp::Custom("-ROT", 3, 3))) || + (is_2dup() && rewrite(AsmOp::Custom("2DUP", 2, 4))) || + (is_2swap() && rewrite(AsmOp::Custom("2SWAP", 2, 4))) || + (is_2over() && rewrite(AsmOp::Custom("2OVER", 2, 4))) || + (is_tuck() && rewrite(AsmOp::Custom("TUCK", 2, 3))) || + (is_2drop() && rewrite(AsmOp::Custom("2DROP", 2, 0))) || (is_xchg2(&i, &j) && rewrite(AsmOp::Xchg2(i, j))) || + (is_xcpu(&i, &j) && rewrite(AsmOp::XcPu(i, j))) || (is_puxc(&i, &j) && rewrite(AsmOp::PuXc(i, j))) || + (is_push2(&i, &j) && rewrite(AsmOp::Push2(i, j))) || (is_blkswap(&i, &j) && rewrite(AsmOp::BlkSwap(i, j))) || + (is_blkpush(&i, &j) && rewrite(AsmOp::BlkPush(i, j))) || (is_blkdrop(&i) && rewrite(AsmOp::BlkDrop(i))) || + (is_push_rot(&i) && rewrite(AsmOp::Push(i), AsmOp::Custom("ROT"))) || + (is_push_rotrev(&i) && rewrite(AsmOp::Push(i), AsmOp::Custom("-ROT"))) || + (is_push_xchg(&i, &j, &k) && rewrite(AsmOp::Push(i), AsmOp::Xchg(j, k))) || + (is_reverse(&i, &j) && rewrite(AsmOp::BlkReverse(i, j))) || + (is_nip_seq(&i, &j) && rewrite(AsmOp::Xchg(i, j), AsmOp::BlkDrop(i))) || + (is_pop_blkdrop(&i, &k) && rewrite(AsmOp::Pop(i), AsmOp::BlkDrop(k))) || + (is_blkdrop2(&i, &j) && rewrite(AsmOp::BlkDrop2(i, j))) || + (is_2pop_blkdrop(&i, &j, &k) && (k >= 3 && k <= 13 && i != j + 1 && i <= 15 && j <= 14 + ? rewrite(AsmOp::Xchg2(j + 1, i), AsmOp::BlkDrop(k + 2)) + : rewrite(AsmOp::Pop(i), AsmOp::Pop(j), AsmOp::BlkDrop(k)))) || + (is_xchg3(&i, &j, &k) && rewrite(AsmOp::Xchg3(i, j, k))) || + (is_xc2pu(&i, &j, &k) && rewrite(AsmOp::Xc2Pu(i, j, k))) || + (is_xcpuxc(&i, &j, &k) && rewrite(AsmOp::XcPuXc(i, j, k))) || + (is_xcpu2(&i, &j, &k) && rewrite(AsmOp::XcPu2(i, j, k))) || + (is_puxc2(&i, &j, &k) && rewrite(AsmOp::PuXc2(i, j, k))) || + (is_puxcpu(&i, &j, &k) && rewrite(AsmOp::PuXcPu(i, j, k))) || + (is_pu2xc(&i, &j, &k) && rewrite(AsmOp::Pu2Xc(i, j, k))) || + (is_push3(&i, &j, &k) && rewrite(AsmOp::Push3(i, j, k))))); } bool Optimizer::find() { @@ -500,17 +613,17 @@ bool Optimizer::optimize() { return f; } -AsmOpConsList optimize_code_head(AsmOpConsList op_list) { - Optimizer opt(std::move(op_list), op_rewrite_comments); +AsmOpConsList optimize_code_head(AsmOpConsList op_list, int mode) { + Optimizer opt(std::move(op_list), op_rewrite_comments, mode); opt.optimize(); return opt.extract_code(); } -AsmOpConsList optimize_code(AsmOpConsList op_list) { +AsmOpConsList optimize_code(AsmOpConsList op_list, int mode) { std::vector> v; while (op_list) { if (!op_list->car->is_comment()) { - op_list = optimize_code_head(std::move(op_list)); + op_list = optimize_code_head(std::move(op_list), mode); } if (op_list) { v.push_back(std::move(op_list->car)); @@ -524,11 +637,13 @@ AsmOpConsList optimize_code(AsmOpConsList op_list) { } void optimize_code(AsmOpList& ops) { - std::unique_ptr op_list; + AsmOpConsList op_list; for (auto it = ops.list_.rbegin(); it < ops.list_.rend(); ++it) { op_list = AsmOpCons::cons(std::make_unique(std::move(*it)), std::move(op_list)); } - op_list = optimize_code(std::move(op_list)); + for (int mode : {1, 1, 1, 1, 0, 0, 0, 0}) { + op_list = optimize_code(std::move(op_list), mode); + } ops.list_.clear(); while (op_list) { ops.list_.push_back(std::move(*(op_list->car))); diff --git a/submodules/ton/tonlib-src/crypto/func/parse-func.cpp b/submodules/ton/tonlib-src/crypto/func/parse-func.cpp index e04077918c..5c44444020 100644 --- a/submodules/ton/tonlib-src/crypto/func/parse-func.cpp +++ b/submodules/ton/tonlib-src/crypto/func/parse-func.cpp @@ -14,10 +14,11 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "func.h" #include "td/utils/crypto.h" +#include "common/refint.h" #include namespace sym { @@ -99,14 +100,21 @@ TypeExpr* parse_type1(Lexer& lex) { lex.cur().error_at("`", "` is not a type identifier"); } } - lex.expect('('); - if (lex.tp() == ')') { + int c; + if (lex.tp() == '[') { lex.next(); - return TypeExpr::new_unit(); + c = ']'; + } else { + lex.expect('('); + c = ')'; + } + if (lex.tp() == c) { + lex.next(); + return c == ')' ? TypeExpr::new_unit() : TypeExpr::new_tuple({}); } auto t1 = parse_type(lex); if (lex.tp() != ',') { - lex.expect(')'); + lex.expect(c); return t1; } std::vector tlist{1, t1}; @@ -114,8 +122,8 @@ TypeExpr* parse_type1(Lexer& lex) { lex.next(); tlist.push_back(parse_type(lex)); } - lex.expect(')'); - return TypeExpr::new_tensor(std::move(tlist)); + lex.expect(c); + return c == ')' ? TypeExpr::new_tensor(std::move(tlist)) : TypeExpr::new_tuple(std::move(tlist)); } TypeExpr* parse_type(Lexer& lex) { @@ -174,6 +182,53 @@ FormalArg parse_formal_arg(Lexer& lex, int fa_idx) { return std::make_tuple(arg_type, new_sym_def, loc); } +void parse_global_var_decl(Lexer& lex) { + TypeExpr* var_type = 0; + SrcLocation loc = lex.cur().loc; + if (lex.tp() == '_') { + lex.next(); + var_type = TypeExpr::new_hole(); + loc = lex.cur().loc; + } else if (lex.tp() != _Ident) { + var_type = parse_type(lex); + } else { + auto sym = sym::lookup_symbol(lex.cur().val); + if (sym && dynamic_cast(sym->value)) { + auto val = dynamic_cast(sym->value); + lex.next(); + var_type = val->get_type(); + } else { + var_type = TypeExpr::new_hole(); + } + } + if (lex.tp() != _Ident) { + lex.expect(_Ident, "global variable name"); + } + loc = lex.cur().loc; + SymDef* sym_def = sym::define_global_symbol(lex.cur().val, false, loc); + if (!sym_def) { + lex.cur().error_at("cannot define global symbol `", "`"); + } + if (sym_def->value) { + auto val = dynamic_cast(sym_def->value); + if (!val) { + lex.cur().error_at("symbol `", "` cannot be redefined as a global variable"); + } + try { + unify(var_type, val->sym_type); + } catch (UnifyError& ue) { + std::ostringstream os; + os << "cannot unify new type " << var_type << " of global variable `" << sym_def->name() + << "` with its previous type " << val->sym_type << ": " << ue; + lex.cur().error(os.str()); + } + } else { + sym_def->value = new SymValGlobVar{glob_var_cnt++, var_type}; + glob_vars.push_back(sym_def); + } + lex.next(); +} + FormalArgList parse_formal_args(Lexer& lex) { FormalArgList args; lex.expect('(', "formal argument list"); @@ -205,6 +260,18 @@ TypeExpr* extract_total_arg_type(const FormalArgList& arg_list) { return TypeExpr::new_tensor(std::move(type_list)); } +void parse_global_var_decls(Lexer& lex) { + lex.expect(_Global); + while (true) { + parse_global_var_decl(lex); + if (lex.tp() != ',') { + break; + } + lex.expect(','); + } + lex.expect(';'); +} + SymValCodeFunc* make_new_glob_func(SymDef* func_sym, TypeExpr* func_type, bool impure = false) { SymValCodeFunc* res = new SymValCodeFunc{glob_func_cnt, func_type, impure}; func_sym->value = res; @@ -239,30 +306,54 @@ bool check_global_func(const Lexem& cur, sym_idx_t func_name = 0) { } } +Expr* make_func_apply(Expr* fun, Expr* x) { + Expr* res; + if (fun->cls == Expr::_Glob) { + if (x->cls == Expr::_Tensor) { + res = new Expr{Expr::_Apply, fun->sym, x->args}; + } else { + res = new Expr{Expr::_Apply, fun->sym, {x}}; + } + res->flags = Expr::_IsRvalue | (fun->flags & Expr::_IsImpure); + } else { + res = new Expr{Expr::_VarApply, {fun, x}}; + res->flags = Expr::_IsRvalue; + } + return res; +} + Expr* parse_expr(Lexer& lex, CodeBlob& code, bool nv = false); -// parse ( E { , E } ) | () | id | num | _ +// parse ( E { , E } ) | () | [ E { , E } ] | [] | id | num | _ Expr* parse_expr100(Lexer& lex, CodeBlob& code, bool nv) { - if (lex.tp() == '(') { + if (lex.tp() == '(' || lex.tp() == '[') { + bool tf = (lex.tp() == '['); + int clbr = (tf ? ']' : ')'); SrcLocation loc{lex.cur().loc}; lex.next(); - if (lex.tp() == ')') { + if (lex.tp() == clbr) { lex.next(); - Expr* res = new Expr{Expr::_Tuple, {}}; + Expr* res = new Expr{Expr::_Tensor, {}}; res->flags = Expr::_IsRvalue; res->here = loc; res->e_type = TypeExpr::new_unit(); + if (tf) { + res = new Expr{Expr::_MkTuple, {res}}; + res->flags = Expr::_IsRvalue; + res->here = loc; + res->e_type = TypeExpr::new_tuple(res->args.at(0)->e_type); + } return res; } Expr* res = parse_expr(lex, code, nv); if (lex.tp() != ',') { - lex.expect(')'); + lex.expect(clbr); return res; } std::vector type_list; type_list.push_back(res->e_type); int f = res->flags; - res = new Expr{Expr::_Tuple, {res}}; + res = new Expr{Expr::_Tensor, {res}}; while (lex.tp() == ',') { lex.next(); auto x = parse_expr(lex, code, nv); @@ -275,8 +366,14 @@ Expr* parse_expr100(Lexer& lex, CodeBlob& code, bool nv) { } res->here = loc; res->flags = f; - res->e_type = TypeExpr::new_tensor(std::move(type_list)); - lex.expect(')'); + res->e_type = TypeExpr::new_tensor(std::move(type_list), !tf); + if (tf) { + res = new Expr{Expr::_MkTuple, {res}}; + res->flags = f; + res->here = loc; + res->e_type = TypeExpr::new_tuple(res->args.at(0)->e_type); + } + lex.expect(clbr); return res; } int t = lex.tp(); @@ -306,7 +403,7 @@ Expr* parse_expr100(Lexer& lex, CodeBlob& code, bool nv) { lex.next(); return res; } - if (t == _Int || t == _Cell || t == _Slice || t == _Builder || t == _Cont || t == _Type) { + if (t == _Int || t == _Cell || t == _Slice || t == _Builder || t == _Cont || t == _Type || t == _Tuple) { Expr* res = new Expr{Expr::_Type, lex.cur().loc}; res->flags = Expr::_IsType; res->e_type = TypeExpr::new_atomic(t); @@ -323,6 +420,16 @@ Expr* parse_expr100(Lexer& lex, CodeBlob& code, bool nv) { lex.next(); return res; } + if (sym && dynamic_cast(sym->value)) { + auto val = dynamic_cast(sym->value); + Expr* res = new Expr{Expr::_GlobVar, lex.cur().loc}; + res->e_type = val->get_type(); + res->sym = sym; + res->flags = Expr::_IsLvalue | Expr::_IsRvalue | Expr::_IsImpure; + lex.next(); + return res; + } + bool auto_apply = false; Expr* res = new Expr{Expr::_Var, lex.cur().loc}; if (nv) { res->val = ~lex.cur().val; @@ -344,6 +451,7 @@ Expr* parse_expr100(Lexer& lex, CodeBlob& code, bool nv) { } else if (val->type == SymVal::_Func) { res->e_type = val->get_type(); res->cls = Expr::_Glob; + auto_apply = val->auto_apply; } else if (val->idx < 0) { lex.cur().error_at("accessing variable `", "` being defined"); } else { @@ -354,6 +462,12 @@ Expr* parse_expr100(Lexer& lex, CodeBlob& code, bool nv) { // std::cerr << "accessing symbol " << lex.cur().str << " : " << res->e_type << (val->impure ? " (impure)" : " (pure)") << std::endl; res->flags = Expr::_IsLvalue | Expr::_IsRvalue | (val->impure ? Expr::_IsImpure : 0); } + if (auto_apply) { + int impure = res->flags & Expr::_IsImpure; + delete res; + res = new Expr{Expr::_Apply, sym, {}}; + res->flags = Expr::_IsRvalue | impure; + } res->deduce_type(lex.cur()); lex.next(); return res; @@ -362,26 +476,10 @@ Expr* parse_expr100(Lexer& lex, CodeBlob& code, bool nv) { return nullptr; } -Expr* make_func_apply(Expr* fun, Expr* x) { - Expr* res; - if (fun->cls == Expr::_Glob) { - if (x->cls == Expr::_Tuple) { - res = new Expr{Expr::_Apply, fun->sym, x->args}; - } else { - res = new Expr{Expr::_Apply, fun->sym, {x}}; - } - res->flags = Expr::_IsRvalue | (fun->flags & Expr::_IsImpure); - } else { - res = new Expr{Expr::_VarApply, {fun, x}}; - res->flags = Expr::_IsRvalue; - } - return res; -} - // parse E { E } Expr* parse_expr90(Lexer& lex, CodeBlob& code, bool nv) { Expr* res = parse_expr100(lex, code, nv); - while (lex.tp() == '(' || (lex.tp() == _Ident && !is_special_ident(lex.cur().val))) { + while (lex.tp() == '(' || lex.tp() == '[' || (lex.tp() == _Ident && !is_special_ident(lex.cur().val))) { if (res->is_type()) { Expr* x = parse_expr100(lex, code, true); x->chk_lvalue(lex.cur()); // chk_lrvalue() ? @@ -446,7 +544,7 @@ Expr* parse_expr80(Lexer& lex, CodeBlob& code, bool nv) { lex.next(); auto x = parse_expr100(lex, code, false); x->chk_rvalue(lex.cur()); - if (x->cls == Expr::_Tuple) { + if (x->cls == Expr::_Tensor) { res = new Expr{Expr::_Apply, name, {obj}}; res->args.insert(res->args.end(), x->args.begin(), x->args.end()); } else { @@ -1168,8 +1266,9 @@ void parse_func_def(Lexer& lex) { } if (val->method_id.is_null()) { val->method_id = std::move(method_id); - } else if (val->method_id != method_id) { - lex.cur().error("integer method identifier for `"s + func_name.str + "` changed to a different value"); + } else if (td::cmp(val->method_id, method_id) != 0) { + lex.cur().error("integer method identifier for `"s + func_name.str + "` changed from " + + val->method_id->to_dec_string() + " to a different value " + method_id->to_dec_string()); } } if (f) { @@ -1191,9 +1290,13 @@ void parse_func_def(Lexer& lex) { bool parse_source(std::istream* is, const src::FileDescr* fdescr) { src::SourceReader reader{is, fdescr}; - Lexer lex{reader, true}; + Lexer lex{reader, true, ";,()[] ~."}; while (lex.tp() != _Eof) { - parse_func_def(lex); + if (lex.tp() == _Global) { + parse_global_var_decls(lex); + } else { + parse_func_def(lex); + } } return true; } diff --git a/submodules/ton/tonlib-src/crypto/func/stack-transform.cpp b/submodules/ton/tonlib-src/crypto/func/stack-transform.cpp index f682b49075..4d9b6a5fc3 100644 --- a/submodules/ton/tonlib-src/crypto/func/stack-transform.cpp +++ b/submodules/ton/tonlib-src/crypto/func/stack-transform.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "func.h" @@ -334,6 +334,13 @@ bool StackTransform::apply_pop(int i) { } } +bool StackTransform::apply_blkpop(int k) { + if (!is_valid() || k < 0) { + return invalidate(); + } + return !k || (touch(k - 1) && shift(k)); +} + bool StackTransform::equal(const StackTransform &other, bool relaxed) const { if (!is_valid() || !other.is_valid()) { return false; @@ -394,6 +401,57 @@ bool StackTransform::is_xchg(int *i, int *j) const { return true; } +bool StackTransform::is_xchg_xchg(int i, int j, int k, int l) const { + if (is_valid() && !d && n <= 4 && (i | j | k | l) >= 0) { + StackTransform t; + return t.apply_xchg(i, j) && t.apply_xchg(k, l) && t <= *this; + } else { + return false; + } +} + +bool StackTransform::is_xchg_xchg(int *i, int *j, int *k, int *l) const { + if (!is_valid() || d || n > 4 || !dp || !is_permutation()) { + return false; + } + if (!n) { + *i = *j = *k = *l = 0; + return true; + } + if (n <= 2) { + *k = *l = 0; + return is_xchg(i, j); + } + if (n == 3) { + // rotation: a -> b -> c -> a + int a = A[0].first; + int b = A[0].second; + int s = (b == A[2].first ? 2 : 1); + int c = A[s].second; + if (b != A[s].first || c != A[3 - s].first || a != A[3 - s].second) { + return false; + } + // implement as XCHG s(a),s(c) ; XCHG s(a),s(b) + *i = *k = a; + *j = c; + *l = b; + return is_xchg_xchg(*i, *j, *k, *l); + } + *i = A[0].first; + *j = A[0].second; + if (get(*j) != *i) { + return false; + } + for (int s = 1; s < 4; s++) { + if (A[s].first != *j) { + *k = A[s].first; + *l = A[s].second; + return get(*l) == *k && is_xchg_xchg(*i, *j, *k, *l); + } + } + return false; +} + bool StackTransform::is_push(int i) const { return is_valid() && d == -1 && n == 1 && A[0].first == -1 && A[0].second == i; } @@ -411,6 +469,7 @@ bool StackTransform::is_push(int *i) const { // 0 2 3 4 .. = pop1 // 1 0 3 4 .. = pop2 // 1 2 0 4 .. = pop3 +// POP s(i) : 1 2 ... i-1 0 i+1 ... ; d=1, n=1, {(i,0)} bool StackTransform::is_pop(int i) const { if (!is_valid() || d != 1 || n > 1 || i < 0) { return false; @@ -436,6 +495,38 @@ bool StackTransform::is_pop(int *i) const { return false; } +// POP s(i) ; POP s(j) : 2 ... i-1 0 i+1 ... j 1 j+2 ... ; d=2, n=2, {(i,0),(j+1,1)} if i <> j+1 +bool StackTransform::is_pop_pop(int i, int j) const { + if (is_valid() && d == 2 && n <= 2 && i >= 0 && j >= 0) { + StackTransform t; + return t.apply_pop(i) && t.apply_pop(j) && t <= *this; + } else { + return false; + } +} + +bool StackTransform::is_pop_pop(int *i, int *j) const { + if (!is_valid() || d != 2 || n > 2) { + return false; + } + if (!n) { + *i = *j = 0; // 2DROP + } else if (n == 2) { + *i = A[0].first - A[0].second; + *j = A[1].first - A[1].second; + if (A[0].second > A[1].second) { + std::swap(*i, *j); + } + } else if (!A[0].second) { + *i = A[0].first; + *j = 0; + } else { + *i = 0; + *j = A[0].first - 1; + } + return is_pop_pop(*i, *j); +} + const StackTransform StackTransform::rot{2, 0, 1, 3}; const StackTransform StackTransform::rot_rev{1, 2, 0, 3}; @@ -447,6 +538,53 @@ bool StackTransform::is_rotrev() const { return equal(rot_rev, true); } +// PUSH i ; ROT == 1 i 0 2 3 +bool StackTransform::is_push_rot(int i) const { + return is_valid() && d == -1 && i >= 0 && is_trivial_after(3) && get(0) == 1 && get(1) == i && get(2) == 0; +} + +bool StackTransform::is_push_rot(int *i) const { + return is_valid() && (*i = get(1)) >= 0 && is_push_rot(*i); +} + +// PUSH i ; -ROT == 0 1 i 2 3 +bool StackTransform::is_push_rotrev(int i) const { + return is_valid() && d == -1 && i >= 0 && is_trivial_after(3) && get(0) == 0 && get(1) == 1 && get(2) == i; +} + +bool StackTransform::is_push_rotrev(int *i) const { + return is_valid() && (*i = get(2)) >= 0 && is_push_rotrev(*i); +} + +// PUSH s(i) ; XCHG s(j),s(k) --> i 0 1 .. i .. +// PUSH s(i) ; XCHG s(0),s(k) --> k-1 0 1 .. k-2 i k .. +bool StackTransform::is_push_xchg(int i, int j, int k) const { + StackTransform t; + return is_valid() && d == -1 && n <= 3 && t.apply_push(i) && t.apply_xchg(j, k) && t <= *this; +} + +bool StackTransform::is_push_xchg(int *i, int *j, int *k) const { + if (!(is_valid() && d == -1 && n <= 3 && n > 0)) { + return false; + } + int s = get(0); + if (s < 0) { + return false; + } + *i = s; + *j = 0; + if (n == 1) { + *k = 0; + } else if (n == 2) { + *k = s + 1; + *i = get(s + 1); + } else { + *j = A[1].first + 1; + *k = A[2].first + 1; + } + return is_push_xchg(*i, *j, *k); +} + // XCHG s1,s(i) ; XCHG s0,s(j) bool StackTransform::is_xchg2(int i, int j) const { StackTransform t; @@ -465,10 +603,9 @@ bool StackTransform::is_xchg2(int *i, int *j) const { if (*i < 0 || *j < 0) { return false; } - if (n != 3) { - return is_xchg2(*i, *j); - } - if (*i) { + if (n == 2 && !*i) { + *j = *i; // XCHG s0,s1 = XCHG2 s0,s0 + } else if (n == 3 && *i) { // XCHG2 s(i),s(i) = XCHG s1,s(i) ; XCHG s0,s(i) : 0->1, 1->i *j = *i; } // XCHG2 s0,s(i) = XCHG s0,s1 ; XCHG s0,s(i) : 0->i, 1->0 @@ -735,6 +872,28 @@ bool StackTransform::is_blkdrop(int *i) const { return false; } +// 0 1 .. j-1 j+i j+i+1 ... +bool StackTransform::is_blkdrop2(int i, int j) const { + if (!is_valid() || d != i || i <= 0 || j < 0 || dp < i + j || n != j || !is_trivial_after(j)) { + return false; + } + for (int s = 0; s < j; s++) { + if (get(s) != s) { + return false; + } + } + return true; +} + +bool StackTransform::is_blkdrop2(int *i, int *j) const { + if (is_valid() && is_blkdrop2(d, n)) { + *i = d; + *j = n; + return true; + } + return false; +} + // equivalent to i times PUSH s(j) bool StackTransform::is_blkpush(int *i, int *j) const { if (!is_valid() || d >= 0) { @@ -800,6 +959,77 @@ bool StackTransform::is_nip_seq(int *i, int *j) const { } } +// POP s(i); BLKDROP k (usually for i >= k >= 0) +bool StackTransform::is_pop_blkdrop(int i, int k) const { + StackTransform t; + return is_valid() && d == k + 1 && t.apply_pop(i) && t.apply_blkpop(k) && t <= *this; +} + +// POP s(i); BLKDROP k == XCHG s0,s(i); BLKDROP k+1 for i >= k >= 0 +// k+1 k+2 .. i-1 0 i+1 .. +bool StackTransform::is_pop_blkdrop(int *i, int *k) const { + if (is_valid() && n == 1 && d > 0 && !A[0].second) { + *k = d - 1; + *i = A[0].first; + return is_pop_blkdrop(*i, *k); + } else { + return false; + } +} + +// POP s(i); POP s(j); BLKDROP k (usually for i<>j >= k >= 0) +bool StackTransform::is_2pop_blkdrop(int i, int j, int k) const { + StackTransform t; + return is_valid() && d == k + 2 && t.apply_pop(i) && t.apply_pop(j) && t.apply_blkpop(k) && t <= *this; +} + +// POP s(i); POP s(j); BLKDROP k == XCHG s0,s(i); XCHG s1,s(j+1); BLKDROP k+2 (usually for i<>j >= k >= 2) +// k+2 k+3 .. i-1 0 i+1 ... j 1 j+2 ... +bool StackTransform::is_2pop_blkdrop(int *i, int *j, int *k) const { + if (is_valid() && n == 2 && d >= 2 && A[0].second + A[1].second == 1) { + *k = d - 2; + int t = (A[0].second > 0); + *i = A[t].first; + *j = A[1 - t].first - 1; + return is_2pop_blkdrop(*i, *j, *k); + } else { + return false; + } +} + +// PUSHCONST c ; ROT == 1 -1000 0 2 3 +bool StackTransform::is_const_rot(int c) const { + return is_valid() && d == -1 && is_trivial_after(3) && get(0) == 1 && c <= c_start && get(1) == c && get(2) == 0; +} + +bool StackTransform::is_const_rot(int *c) const { + return is_valid() && (*c = get(1)) <= c_start && is_const_rot(*c); +} + +// PUSHCONST c ; POP s(i) == 0 1 .. i-1 -1000 i+1 ... +bool StackTransform::is_const_pop(int c, int i) const { + return is_valid() && !d && n == 1 && i > 0 && c <= c_start && get(i - 1) == c; +} + +bool StackTransform::is_const_pop(int *c, int *i) const { + if (is_valid() && !d && n == 1 && A[0].second <= c_start) { + *i = A[0].first + 1; + *c = A[0].second; + return is_const_pop(*c, *i); + } else { + return false; + } +} + +// PUSH i ; PUSHCONST c == c i 0 1 2 ... +bool StackTransform::is_push_const(int i, int c) const { + return is_valid() && d == -2 && c <= c_start && i >= 0 && is_trivial_after(2) && get(0) == c && get(1) == i; +} + +bool StackTransform::is_push_const(int *i, int *c) const { + return is_valid() && d == -2 && n == 2 && is_push_const(*i = get(1), *c = get(0)); +} + void StackTransform::show(std::ostream &os, int mode) const { if (!is_valid()) { os << ""; diff --git a/submodules/ton/tonlib-src/crypto/func/test/a10.fc b/submodules/ton/tonlib-src/crypto/func/test/a10.fc new file mode 100644 index 0000000000..70c7871d70 --- /dev/null +++ b/submodules/ton/tonlib-src/crypto/func/test/a10.fc @@ -0,0 +1,9 @@ +_ f(int a, int x) { + int y = 0; + int z = 0; + while ((y = x * x) > a) { + x -= 1; + z = 1; + } + return (y, z); +} diff --git a/submodules/ton/tonlib-src/crypto/func/test/a11.fc b/submodules/ton/tonlib-src/crypto/func/test/a11.fc new file mode 100644 index 0000000000..45bdf1f368 --- /dev/null +++ b/submodules/ton/tonlib-src/crypto/func/test/a11.fc @@ -0,0 +1,28 @@ +_ f(slice ds, int total_weight, int elect_at, cell frozen, int total_stakes, int cnt, cell credits, cell vdict, int elect) { + return (ds, elect, credits); +} + +_ g(slice ds, int total_weight, int elect_at, cell frozen, int total_stakes, int cnt, cell credits, int elect) { + return (ds, elect, credits); +} + +_ h(slice ds, int total_weight, int elect_at, cell frozen, int total_stakes, cell credits, int elect) { + return (ds, elect, credits); +} + +_ h2(slice ds, int total_weight, int elect_at, cell frozen, int total_stakes, cell credits, int elect) { + return (ds, credits, elect); +} + +_ h3(int pubkey, int adnl_addr, int stake, int tot_weight, tuple vinfo) { + return (pubkey, tot_weight, stake, vinfo); +} + +_ z(int a, int b) { + return (b, 0, a); +} + +_ z2(int a, int b) { + return (0, a, b); +} + diff --git a/submodules/ton/tonlib-src/crypto/func/test/a6_4.fc b/submodules/ton/tonlib-src/crypto/func/test/a6_4.fc new file mode 100644 index 0000000000..d7e6596a09 --- /dev/null +++ b/submodules/ton/tonlib-src/crypto/func/test/a6_4.fc @@ -0,0 +1,20 @@ +var calc_root(m) { + int base = 1; + repeat(70) { base *= 10; } + var (a, b, c) = (1, 0, - m); + var (p1, q1, p2, q2) = (1, 0, 0, 1); + do { + int k = -1; + var (a1, b1, c1) = (0, 0, 0); + do { + k += 1; + (a1, b1, c1) = (a, b, c); + c += b; + c += b += a; + } until (c > 0); + (a, b, c) = (- c1, - b1, - a1); + (p1, q1) = (k * p1 + q1, p1); + (p2, q2) = (k * p2 + q2, p2); + } until (p1 > base); + return (p1, q1, p2, q2); +} diff --git a/submodules/ton/tonlib-src/crypto/func/test/a6_5.fc b/submodules/ton/tonlib-src/crypto/func/test/a6_5.fc new file mode 100644 index 0000000000..ece7cd38d2 --- /dev/null +++ b/submodules/ton/tonlib-src/crypto/func/test/a6_5.fc @@ -0,0 +1,20 @@ +var twice(f, x) { + return f (f x); +} + +_ sqr(x) { + return x * x; +} + +var main(x) { + var f = sqr; + return twice(f, x) * f(x); +} + +var pow6(x) { + return twice(sqr, x) * sqr(x); +} + +_ q() { + return false; +} diff --git a/submodules/ton/tonlib-src/crypto/func/test/c1.fc b/submodules/ton/tonlib-src/crypto/func/test/c1.fc new file mode 100644 index 0000000000..1a07baca10 --- /dev/null +++ b/submodules/ton/tonlib-src/crypto/func/test/c1.fc @@ -0,0 +1,37 @@ +global int x, y, z; +global (cell, slice) y; +global ((int, int) -> int) op; + +_ get() { + var t = z + 1; + return x; +} + +_ pre_next() { + return x + 1; +} + +() init() impure { + ;; global x; + x = 0; +} + +int next() impure { + ;; global x; + return x += 1; +} + +_ set_y(x, w) { + y = (w, x); +} + +_ get_y() impure { + return y; +} + +int main(int c) { + init(); + c += next(); + return c + pre_next(); +} + diff --git a/submodules/ton/tonlib-src/crypto/func/test/c2.fc b/submodules/ton/tonlib-src/crypto/func/test/c2.fc new file mode 100644 index 0000000000..277c70530a --- /dev/null +++ b/submodules/ton/tonlib-src/crypto/func/test/c2.fc @@ -0,0 +1,10 @@ +global ((int, int) -> int) op; + +int check_assoc(int a, int b, int c) { + return op(op(a, b), c) == op(a, op(b, c)); +} + +int main() { + op = _+_; + return check_assoc(2, 3, 9); +} diff --git a/submodules/ton/tonlib-src/crypto/func/test/c2_1.fc b/submodules/ton/tonlib-src/crypto/func/test/c2_1.fc new file mode 100644 index 0000000000..3bf863a6d7 --- /dev/null +++ b/submodules/ton/tonlib-src/crypto/func/test/c2_1.fc @@ -0,0 +1,7 @@ +_ check_assoc(op, a, b, c) { + return op(op(a, b), c) == op(a, op(b, c)); +} + +int main() { + return check_assoc(_+_, 2, 3, 9); +} diff --git a/submodules/ton/tonlib-src/crypto/func/test/w8.fc b/submodules/ton/tonlib-src/crypto/func/test/w8.fc new file mode 100644 index 0000000000..bd0696e736 --- /dev/null +++ b/submodules/ton/tonlib-src/crypto/func/test/w8.fc @@ -0,0 +1,22 @@ +int check_signatures(msg_hash, signatures, signers, bitmask_size) impure { + var bitmask = 0; + var id = -1; + do { + (id, var signature, var f) = signatures.udict_get_next?(32, id); + if (f){ + var sig = signature.preload_bits(512); + var public_key = -1; + do { + (public_key, var cs, var _found) = signers.udict_get_next?(256, public_key); + if (_found){ + if (check_signature(msg_hash, sig, public_key)){ + var signer_index = cs~load_uint(bitmask_size); + bitmask = bitmask | (1 << (signer_index - 1)); + } + } + } until (~ _found); + ;; signature~touch(); + } + } until (~ f); + return bitmask; +} diff --git a/submodules/ton/tonlib-src/crypto/func/test/w9.fc b/submodules/ton/tonlib-src/crypto/func/test/w9.fc new file mode 100644 index 0000000000..d943554210 --- /dev/null +++ b/submodules/ton/tonlib-src/crypto/func/test/w9.fc @@ -0,0 +1,8 @@ +_ g(s) { + var (z, t) = (17, s); + while (z > 0) { + t = s; + z -= 1; + } + return ~ t; +} diff --git a/submodules/ton/tonlib-src/crypto/func/unify-types.cpp b/submodules/ton/tonlib-src/crypto/func/unify-types.cpp index 698d21feba..0a10141624 100644 --- a/submodules/ton/tonlib-src/crypto/func/unify-types.cpp +++ b/submodules/ton/tonlib-src/crypto/func/unify-types.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "func.h" @@ -47,6 +47,12 @@ void TypeExpr::compute_width() { maxw = w_inf; } break; + case te_Tuple: + minw = maxw = 1; + for (TypeExpr* arg : args) { + arg->compute_width(); + } + break; case te_Indirect: minw = args[0]->minw; maxw = args[0]->maxw; @@ -84,6 +90,14 @@ bool TypeExpr::recompute_width() { } return true; } + case te_Tuple: { + for (TypeExpr* arg : args) { + if (arg->minw > 1 || arg->maxw < 1 || arg->minw > arg->maxw) { + return false; + } + } + return true; + } default: return false; } @@ -233,7 +247,9 @@ std::ostream& TypeExpr::print(std::ostream& os, int lex_level) { } } case te_Tensor: { - os << "("; + if (lex_level > -127) { + os << "("; + } auto c = args.size(); if (c) { for (const auto& x : args) { @@ -243,7 +259,25 @@ std::ostream& TypeExpr::print(std::ostream& os, int lex_level) { } } } - return os << ")"; + if (lex_level > -127) { + os << ")"; + } + return os; + } + case te_Tuple: { + os << "["; + auto c = args.size(); + if (c == 1 && args[0]->constr == te_Tensor) { + args[0]->print(os, -127); + } else if (c) { + for (const auto& x : args) { + x->print(os); + if (--c) { + os << ", "; + } + } + } + return os << "]"; } case te_Map: { assert(args.size() == 2); @@ -312,7 +346,7 @@ void check_update_widths(TypeExpr* te1, TypeExpr* te2) { check_width_compat(te1, te2); te1->minw = te2->minw = std::max(te1->minw, te2->minw); te1->maxw = te2->maxw = std::min(te1->maxw, te2->maxw); - assert(te1->minw <= te2->minw); + assert(te1->minw <= te1->maxw); } void unify(TypeExpr*& te1, TypeExpr*& te2) { diff --git a/submodules/ton/tonlib-src/crypto/parser/symtable.h b/submodules/ton/tonlib-src/crypto/parser/symtable.h index 6c77ca7b03..88f683bd3e 100644 --- a/submodules/ton/tonlib-src/crypto/parser/symtable.h +++ b/submodules/ton/tonlib-src/crypto/parser/symtable.h @@ -32,7 +32,7 @@ namespace sym { typedef int var_idx_t; struct SymValBase { - enum { _Param, _Var, _Func, _Typename }; + enum { _Param, _Var, _Func, _Typename, _GlobVar }; int type; int idx; SymValBase(int _type, int _idx) : type(_type), idx(_idx) { diff --git a/submodules/ton/tonlib-src/crypto/smartcont/CreateState.fif b/submodules/ton/tonlib-src/crypto/smartcont/CreateState.fif index ed82499b5f..1330a446f1 100644 --- a/submodules/ton/tonlib-src/crypto/smartcont/CreateState.fif +++ b/submodules/ton/tonlib-src/crypto/smartcont/CreateState.fif @@ -242,3 +242,7 @@ dictnew constant special-dict register_smc Masterchain swap 6 .Addr cr } : create-wallet0 + +{ dup tlb-type-lookup { nip } { "unknown TLB type " swap $+ abort } cond } : $>tlb +{ bl word $>tlb 1 'nop } ::_ tlb: +{ [-o] (add|update|prolong) ... " +cr +tab + +"Creates the internal message body containing a request to automatic DNS smart contract created by new-auto-dns.fif, " + +"to be sent later with a suitable payment from a wallet to , and saves it into ('" savefile $+ +"' by default). " + +"The operation to be performed is one of" +cr +tab + +"add { owner | cat (smc | next | adnl | text ) }" +cr +tab + +"update { owner | cat (smc | next | adnl | text ) }" +cr +tab + +"prolong " + disable-digit-options generic-help-setopt + "o" "--output" { =: savefile } short-long-option-arg + "Sets output file for generated initialization message ('" savefile $+ +"' by default)" option-help + "h" "--help" { usage } short-long-option + "Shows a help message" option-help +parse-options + +$# 4 < ' usage if +4 :$1..n + +$1 true parse-load-address =: bounce 2=: dest-addr +$2 dup =: main-op-name atom =: main-op +$3 dup =: subdomain $len 127 > abort"subdomain name too long" +$4 parse-int dup 30 1<< < { now + } if =: expire-at + +{ $* @ dup null? { second $@ ! } { drop } cond } : @skip +{ $* @ null? } : @end? +{ $* @ uncons $* ! } : @next +{ @next drop } 4 times + +main-op dup `add eq? over `update eq? or swap `prolong eq? or +{ "unknown main operation '" main-op-name $+ +"'; one of 'add', 'update' or 'prolong' expected" abort } ifnot +main-op `prolong eq? not =: need-params + +$# 4 > need-params <> abort"extra parameters, or no parameters for chosen main operation" + +variable Values dictnew Values ! +// ( i c -- ) +{ over 0= abort"category cannot be zero" + idict!+ not abort"duplicate category id" + Values ! +} : register-value + +{ @end? abort"category number expected" @next (number) 1 <> abort"category must be integer" + dup 16 fits not abort"category does not fit into 16 bit integer" + dup 0= abort"category must be non-zero" +} : parse-cat-num +{ @end? abort"smart contract address expected" + @next false parse-load-address drop +} : cl-parse-smc-addr +{ @end? abort"adnl address expected" + @next parse-adnl-addr +} : cl-parse-adnl-addr +{ } : serialize-smc-addr +{ } : serialize-next-resolver +{ } : serialize-adnl-addr +{ } : serialize-text +{ @end? abort"subdomain record value expected" @next + dup "smc" $= { drop cl-parse-smc-addr serialize-smc-addr } { + dup "next" $= { drop cl-parse-smc-addr serialize-next-resolver } { + dup "adnl" $= { drop cl-parse-adnl-addr serialize-adnl-addr } { + dup "text" $= { drop @next serialize-text } { + "unknown record type "' swap $+ +"'" abort + } cond } cond } cond } cond +} : parse-value +{ @next dup "owner" $= { drop -2 cl-parse-smc-addr serialize-smc-addr } { + dup "cat" $= { drop parse-cat-num parse-value } { + "unknown action '" swap $+ +"'" abort + } cond } cond + register-value +} : parse-action +{ { @end? not } { parse-action } while } : parse-actions +parse-actions + +// ( S -- S1 .. Sn n ) +{ 1 swap { dup "." $pos dup 0>= } { $| 1 $| nip rot 1+ swap } while drop swap +} : split-by-dots +// ( S -- s ) +{ dup $len dup 0= abort"subdomain cannot be empty" 126 > abort"subdomain too long" + dup 0 chr $pos 1+ abort"subdomain contains null characters" + split-by-dots s + +main-op ( _( `add 0x72656764 ) _( `update 0x75706464 ) _( `prolong 0x70726f6c ) ) +assq-val not abort"unknown main operation" +=: op-id + +."Automatic DNS smart contract address = " dest-addr 2dup .addr cr 6 .Addr cr + +."Action: " main-op .l subdomain type space expire-at . cr +."Operation code: 0x" op-id 8 0X. cr +."Value: " +Values @ dup null? { drop ."(none)" } { =: actions-builder + +// create an internal message +now 32 << actions-builder hashu 32 1<<1- and + =: query_id +s tuck sbits 8 / 7 i, swap s, + main-op `prolong eq? { Values @ ref, } ifnot + expire-at 32 u, b> +dup ."Internal message body is: " B dup Bx. cr +."Query_id is " query_id dup . ."= 0x" X. cr +savefile tuck B>file +."(Saved to file " type .")" cr diff --git a/submodules/ton/tonlib-src/crypto/smartcont/auto/config-code.cpp b/submodules/ton/tonlib-src/crypto/smartcont/auto/config-code.cpp index 91b450367d..45f74a0656 100644 --- a/submodules/ton/tonlib-src/crypto/smartcont/auto/config-code.cpp +++ b/submodules/ton/tonlib-src/crypto/smartcont/auto/config-code.cpp @@ -1 +1 @@ -with_tvm_code("config", "te6ccgECJwEAA48AART/APSkE/Sg8sgLAQIBIAIDAgLHBAUCAvEjJAIBzQYHAAaqglsCASAICQIBIBUWAgEgCgsCASAQEQIBIAwNAgEgDg8A6QB0NMD+kAwIPpEAaQDcbATsSPHALGSXwPgAtMf0z8ighBOVlNUuo49MgHU0XH4MyBukjB/lNDXC//iA3AEupsyIfAEIfgjvAK8sJEC4p2AJFjwAYIQ7nZPS/AG4DGCEO52T2/wB+AQJF8EIMAAAYMesLHypYAAlO1E0NRQM4Ag9BXIzAHPFsntVIAApO1E0NTTH9P/IMcAkW2T9AQB4gHRgABsyBTMEssfy//0AMntVIAIBIBITAgEgFBQANzQ0wcBpu9+sPJJ0x/TH9MP0w8wIMIA8om+8omAAKxwgBjIywVQBc8WFMtuyx/LP8kB+wCAACSAQPAFgAgEgFxgCASAdHgIBIBkaAgEgGxwAWxx+DPQ1wv/+COCEE5Db2RwggDE/8jLEBTL/4Md+gITy2oSyx/LPwHPFslw+wCAAoQhghBDZlAhupwx0x/U0UATgCD0FQHgIYIQTkNvZLqOEDHUIfsE7UMC7VMB8QaC8gDgIYIQUGJLIbqVMTHT/9HgIYIQTkPvBbqTMfAI4DDyYIAEBICYAOTTB4AgsxKwwFPyqdMfAYIQjoEnirryqdP/0z8wgAgEgHyACASAhIgAfHAgcMjKAMs/y/8BzxbJ0IAANPQE0z/T/4AAZMgU9AASyz/L/wHPFoABFFsBcbCeIPkBMSGDB/QOb6ExkN+d1wv/IYMH9A5voTHyquKAArQw7UTQ1IAggCRTMfRqIG6TECNbjjgg0CDXScInjinTB9cLHwHAEfgjEr6wjhUBgCJUEET0blRTIfRuMIAkQBP0WjCTECNb4pQQNF8D4uLIzAHPFsntVIAHZIMI1xgg0x/TH9Mf+CMSufJj7UTQ1NMf0/8gxwCRbZP0BAHiAdFRUrryoSWCEFZvdGWhfrCK4Qb5AVQQdvkQ8qL4AAWkVHUEJcgUzBLLH8v/9ADJ7VT4DxA1RFXwCUMDyBTMEssfy//0AMntVICUBqgPTDyHbPNMHgCCzErDAU/Kp0x8BghCOgSeKuvKp0//TPzAJ+QFAqvkQ8qL4AAGkVHIDJ8gUzBLLH8v/9ADJ7VT4DxA1RxbwD8gUzBLLH8v/9ADJ7VQmADaAIvgzIG6SW23g0IBo1yHIAc8WyYAQ9A5voTA="); +with_tvm_code("config", "te6ccgECHQEAA5oAART/APSkE/S88sgLAQIBIAIDAgFIBAUCAvEYGQICxQYHABGgmS/aiaGuFj8CAc0ICQAGqoJbAgEgCgsCASATFAIBSAwNAgEgDg8A6wB0NMD+kAwIPpEAaQDcbATsSPHALGSXwPgAtMf0z8ighBOVlNUuo4+bBLU0XH4MyBukjB/lNDXC//iA3AEup0yIfAE+CNSILwCvLAC3gKdgCRY8AGCEO52T0vwBuAxghDudk9v8AfgECRfBCDAAAGDHrCx8qWAAJTtRNDUUDOAIPQVyMwBzxbJ7VSACASAQEQIBIBISADM0NMHAcAS8onTH9Mf0w/TDzAgwgDyib7yiYAArHCAGMjLBVAFzxYUy27LH8s/yQH7AIAAJIBA8AWACAUgVFgHh8CuNhNkfyAqYNBg/oHN9DPkeuF/6mDQYP6BzfQkHlVcUwagnoCaZ/p/8wYNqoKgzggCfEojF7KmLaZOADvKalACHoHN9CYya+ENvBAEGR8EeeAoDHACHohgdAQU4GBVQAJXk0ttgkBQYP6LZgA8C0KQXAFscfgz0NcL//gjghBOQ29kcIIAxP/IyxAUy/+DHfoCE8tqEssfyz8BzxbJcPsAgAKcIYIQQ2ZQIbqcMdMf1NFAE4Ag9BUB4CGCEE5Db2S6jhMx1CH7BO1DAtDtHu1TAfEGgvIA4CGCEFBiSyG6lWwh0//R4CGCEE5D7wW6kzHwCOAw8mCAAJAPI9AASyz/L/wHPFgKDB/RDbQChDDtRNDUgCCAJFMx9GogbpFbjjMg0CDXScInjibTB9cLH/gjuwHAErCOFYAiWFFE9G5UUyH0bjCAJEAT9FowAZFb4pJfA+LiAcjMAc8Wye1UgAccgwjXGCDTH9Mf0x/4IxK58mPtRNDU0x/T//QE0VFSuvKhJYIQVm90ZaF+sIrhBvkBVBB2+RDyovgABaRUdQQlA8jMEssfy//0AMntVPgPEDVEVfAJQwMDyMwSyx/L//QAye1UgGgLWA9MPIds8AdMHgCCzErDAU/Kp0x8BghCOgSeKuvKp0//TPzAK+QFAu/kQ8qL4AAKkVHMEKAPIzBLLH8v/9ADJ7VT4D4Ai+DP5ABBXEDQQI0iQ8A9Uc0IkA8jMEssfy//0AMntVCBukl8FiuIbHABOgCL4MyBuk1ttcODQ0wcBwBLyqIBg1yHTP8gBzxbJEoAQ9A5voTABAC7THxA0ECTwCUMDA8jMEssfy//0AMntVA=="); diff --git a/submodules/ton/tonlib-src/crypto/smartcont/auto/config-code.fif b/submodules/ton/tonlib-src/crypto/smartcont/auto/config-code.fif index 4899527fc1..585f03b666 100644 --- a/submodules/ton/tonlib-src/crypto/smartcont/auto/config-code.fif +++ b/submodules/ton/tonlib-src/crypto/smartcont/auto/config-code.fif @@ -13,12 +13,13 @@ PROGRAM{ DECLPROC perform_action DECLPROC get_validator_descr DECLPROC unpack_validator_descr - DECLPROC create_new_entry - DECLPROC unpack_suggestion - DECLPROC pack_suggestion + DECLPROC new_proposal + DECLPROC unpack_proposal + DECLPROC pack_proposal DECLPROC register_vote DECLPROC recv_external DECLPROC run_ticktock + 85143 DECLMETHOD seqno set_conf_param PROC:<{ // index value c4 PUSH // index value _3 @@ -38,24 +39,16 @@ PROGRAM{ // c4 PUSH // _1 CTOS // cs - LDREF // _6 cs - 32 LDU // _6 _8 cs - 256 LDU // cfg_dict stored_seqno public_key cs - DUP // cfg_dict stored_seqno public_key cs cs - SEMPTY // cfg_dict stored_seqno public_key cs _15 - IF:<{ // cfg_dict stored_seqno public_key cs - NEWDICT // cfg_dict stored_seqno public_key cs _16 - }>ELSE<{ // cfg_dict stored_seqno public_key cs - LDDICT // cfg_dict stored_seqno public_key _16 cs - SWAP // cfg_dict stored_seqno public_key cs _16 - }> // cfg_dict stored_seqno public_key cs vote_dict - SWAP // cfg_dict stored_seqno public_key vote_dict cs + LDREF // _4 cs + 32 LDU // _4 _6 cs + 256 LDU // _4 _6 _9 cs + LDDICT // res res res res cs ENDS }> store_data PROC:<{ // cfg_dict stored_seqno public_key vote_dict - NEWC // cfg_dict stored_seqno public_key vote_dict _4 - s1 s4 XCHG // vote_dict stored_seqno public_key cfg_dict _4 + s0 s3 XCHG + NEWC // vote_dict stored_seqno public_key cfg_dict _4 STREF // vote_dict stored_seqno public_key _5 s1 s2 XCHG // vote_dict public_key stored_seqno _5 32 STU // vote_dict public_key _7 @@ -69,19 +62,17 @@ PROGRAM{ CTOS // cs 8 LDU // _4 cs SWAP // cs _4 - -17 ADDCONST // cs _8 - -2 PUSHINT // cs _8 _9=-2 - AND // cs _10 - 9 THROWIF + 18 EQINT // cs _8 + 9 THROWIFNOT 32 LDU // utime_since cs 32 LDU // utime_since utime_until cs 16 LDU // utime_since utime_until total cs - 16 LDU // utime_since utime_until total _44 _43 + 16 LDU // utime_since utime_until total _42 _41 DROP // utime_since utime_until total main DUP // utime_since utime_until total main main - 0 GTINT // utime_since utime_until total main _30 + 0 GTINT // utime_since utime_until total main _28 9 THROWIFNOT - GEQ // utime_since utime_until _33 + GEQ // utime_since utime_until _31 9 THROWIFNOT }> send_answer PROC:<{ @@ -139,8 +130,7 @@ PROGRAM{ 1314280276 PUSHINT // s_addr src_addr tag query_id in_msg tag _29=1314280276 EQUAL // s_addr src_addr tag query_id in_msg _30 IFJMP:<{ // s_addr src_addr tag query_id in_msg - s2 POP // s_addr src_addr in_msg query_id - SWAP // s_addr src_addr query_id in_msg + 1 2 BLKDROP2 // s_addr src_addr query_id in_msg LDREF // s_addr src_addr query_id vset in_msg ENDS 1 PUSHINT // s_addr src_addr query_id vset _36=1 @@ -162,17 +152,17 @@ PROGRAM{ s2 POP // s_addr vset query_id OVER // s_addr vset query_id vset check_validator_set CALLDICT // s_addr vset query_id t_since t_until - OVER - NOW // s_addr vset query_id t_since t_until t_since t + NOW // s_addr vset query_id t_since t_until t + s2 s(-1) PUXC // s_addr vset query_id t_since t_until t_since t GREATER // s_addr vset query_id t_since t_until _53 s0 s2 XCHG // s_addr vset query_id _53 t_until t_since GREATER // s_addr vset query_id _53 _54 AND // s_addr vset query_id ok - }>ELSE<{ - s0 s2 XCHG // s_addr vset query_id ok - }> + s0 s2 XCHG // s_addr ok query_id vset + }> // s_addr ok query_id vset + s0 s2 XCHG // s_addr vset query_id ok IFJMP:<{ // s_addr vset query_id - 36 PUSHINT // s_addr vset query_id _56=36 + 36 PUSHINT ROT // s_addr query_id _56=36 vset set_conf_param CALLDICT 4000730955 PUSHINT // s_addr query_id _58=4000730955 @@ -248,23 +238,24 @@ PROGRAM{ SETCODE c3 PUSH // cfg_dict public_key new_code cs old_code s0 s2 XCHG // cfg_dict public_key old_code cs new_code + CTOS // cfg_dict public_key old_code cs _25 + BLESS // cfg_dict public_key old_code cs _26 c3 POP SWAP // cfg_dict public_key cs old_code after_code_upgrade CALLDICT 0 THROW }> // cfg_dict public_key action cs OVER - 1348619041 PUSHINT // cfg_dict public_key action cs action _29=1348619041 - EQUAL // cfg_dict public_key action cs _30 + 1348619041 PUSHINT // cfg_dict public_key action cs action _31=1348619041 + EQUAL // cfg_dict public_key action cs _32 IFJMP:<{ // cfg_dict public_key action cs - NIP - NIP // cfg_dict cs + 2 1 BLKDROP2 // cfg_dict cs 256 LDU // cfg_dict public_key cs ENDS }> // cfg_dict public_key action cs OVER - 1313074949 PUSHINT // cfg_dict public_key action cs action _35=1313074949 - EQUAL // cfg_dict public_key action cs _36 + 1313074949 PUSHINT // cfg_dict public_key action cs action _37=1313074949 + EQUAL // cfg_dict public_key action cs _38 IFJMP:<{ // cfg_dict public_key action cs NIP // cfg_dict public_key cs change_elector_code CALLDICT @@ -281,18 +272,26 @@ PROGRAM{ IFJMP:<{ // idx vset 2DROP // PUSHNULL // _5 + 0 PUSHINT // _5 _6=0 }> // idx vset CTOS // idx cs - 104 PUSHINT // idx cs _17 + 8 LDU // idx _10 cs + SWAP // idx cs _10 + 18 EQINT // idx cs _14 + 40 THROWIFNOT + 96 PUSHINT // idx cs _23 SDSKIPFIRST // idx cs - NEWC // idx cs _20 - SWAP // idx _20 cs - STSLICER // idx _21 - ENDC // idx dict - 16 PUSHINT // idx dict _25=16 + 64 LDU // idx total_weight cs + NEWC // idx total_weight cs _30 + SWAP // idx total_weight _30 cs + STSLICER // idx total_weight _31 + ENDC // idx total_weight dict + s1 s2 XCHG + 16 PUSHINT // total_weight idx dict _35=16 DICTUGET - NULLSWAPIFNOT // _27 _28 - DROP // value + NULLSWAPIFNOT // total_weight _41 _42 + DROP // total_weight value + SWAP // value total_weight }> unpack_validator_descr PROC:<{ // cs @@ -312,30 +311,22 @@ PROGRAM{ 64 LDU // _18 _31 _30 DROP // _18 _21 }> - create_new_entry PROC:<{ + new_proposal PROC:<{ // cs - 0 PUSHINT // cs _1=0 - DUP // cs _1=0 _2=0 - FALSE // cs _1=0 _2=0 _3 - NEWC // cs _1=0 _2=0 _3 _4 - 1 STI // cs _1=0 _2=0 _6 - 64 STU // cs _1=0 _8 - 256 STU // cs _10 - SWAP // _10 cs - STSLICER // _11 - ENDC // _12 - CTOS // _13 + PUSHNULL // cs _1 + 0 PUSHINT // cs _1 _2=0 + s0 s1 s2 XCPUXC // _1 _2=0 _3=0 cs }> - unpack_suggestion PROC:<{ + unpack_proposal PROC:<{ // cs LDDICT // _1 cs 64 LDU // _1 _3 cs 256 LDU // _1 _3 _6 cs }> - pack_suggestion PROC:<{ + pack_proposal PROC:<{ // voters sum_weight vset_id body - NEWC // voters sum_weight vset_id body _4 - s1 s4 XCHG // body sum_weight vset_id voters _4 + s0 s3 XCHG + NEWC // body sum_weight vset_id voters _4 STDICT // body sum_weight vset_id _5 s1 s2 XCHG // body vset_id sum_weight _5 64 STU // body vset_id _7 @@ -344,31 +335,87 @@ PROGRAM{ STSLICER // _10 }> register_vote PROC:<{ - // vote_dict action cs idx weight - 2DROP // vote_dict action cs - SWAP - 1 PUSHINT // vote_dict cs action _9=1 - AND // vote_dict cs _10 - IF:<{ // vote_dict cs - DUP // vote_dict cs cs - HASHSU // vote_dict cs _11 - NIP // vote_dict hash - OVER - 8 PUSHPOW2 // vote_dict hash vote_dict _13=256 + // vote_dict action cs idx weight total_weight cur_vset_id + s0 s5 XCHG + 1 PUSHINT // vote_dict cur_vset_id cs idx weight total_weight action _13=1 + AND // vote_dict cur_vset_id cs idx weight total_weight _14 + IF:<{ // vote_dict cur_vset_id cs idx weight total_weight + s3 PUSH // vote_dict cur_vset_id cs idx weight total_weight cs + HASHSU // vote_dict cur_vset_id cs idx weight total_weight hash + s0 s6 PUSH2 + 8 PUSHPOW2 // vote_dict cur_vset_id cs idx weight total_weight hash hash vote_dict _16=256 DICTUGET - NULLSWAPIFNOT // vote_dict _23 _24 - NIP // vote_dict found? - IFNOT:<{ // vote_dict - }> // vote_dict - }>ELSE<{ // vote_dict cs - 256 PLDU // vote_dict hash - OVER - 8 PUSHPOW2 // vote_dict hash vote_dict _19=256 + NULLSWAPIFNOT // vote_dict cur_vset_id cs idx weight total_weight hash entry found? + }>ELSE<{ // vote_dict cur_vset_id cs idx weight total_weight + s3 PUSH // vote_dict cur_vset_id cs idx weight total_weight cs + 256 PLDU // vote_dict cur_vset_id cs idx weight total_weight hash + s0 s6 PUSH2 + 8 PUSHPOW2 // vote_dict cur_vset_id cs idx weight total_weight hash hash vote_dict _20=256 DICTUGET - NULLSWAPIFNOT // vote_dict _25 _26 - NIP // vote_dict found? + NULLSWAPIFNOT // vote_dict cur_vset_id cs idx weight total_weight hash entry found? + DUP // vote_dict cur_vset_id cs idx weight total_weight hash entry found? found? 42 THROWIFNOT }> + IF:<{ // vote_dict cur_vset_id cs idx weight total_weight hash entry + s5 POP // vote_dict cur_vset_id entry idx weight total_weight hash + s0 s4 XCHG // vote_dict cur_vset_id hash idx weight total_weight entry + unpack_proposal INLINECALLDICT // vote_dict cur_vset_id hash idx weight total_weight _65 _66 _67 _68 + }>ELSE<{ // vote_dict cur_vset_id cs idx weight total_weight hash entry + DROP // vote_dict cur_vset_id cs idx weight total_weight hash + PUSHNULL // vote_dict cur_vset_id cs idx weight total_weight hash _30 + s5 s0 s6 XC2PU + 0 PUSHINT + s0 s1 s3 XCHG3 // vote_dict cur_vset_id hash idx weight total_weight _65 _66 _67 _68 + }> // vote_dict cur_vset_id hash idx weight total_weight voters sum_weight vset_id body + s1 s8 XCPU // vote_dict cur_vset_id hash idx weight total_weight voters sum_weight body vset_id cur_vset_id + NEQ // vote_dict cur_vset_id hash idx weight total_weight voters sum_weight body _32 + IF:<{ // vote_dict cur_vset_id hash idx weight total_weight voters sum_weight body + NIP + PUSHNULL + s2 POP + 0 PUSHINT + SWAP // vote_dict cur_vset_id hash idx weight total_weight voters sum_weight=0 body + }> // vote_dict cur_vset_id hash idx weight total_weight voters sum_weight body + s5 s2 PUSH2 + 16 PUSHINT // vote_dict cur_vset_id hash idx weight total_weight voters sum_weight body idx voters _37=16 + DICTUGET + NULLSWAPIFNOT // vote_dict cur_vset_id hash idx weight total_weight voters sum_weight body _73 _74 + NIP // vote_dict cur_vset_id hash idx weight total_weight voters sum_weight body found? + IFJMP:<{ // vote_dict cur_vset_id hash idx weight total_weight voters sum_weight body + 8 BLKDROP // vote_dict + PUSHNULL // vote_dict _60 + }> // vote_dict cur_vset_id hash idx weight total_weight voters sum_weight body + 32 PUSHINT // vote_dict cur_vset_id hash idx weight total_weight voters sum_weight body _40=32 + NEWC // vote_dict cur_vset_id hash idx weight total_weight voters sum_weight body _40=32 _41 + NOW // vote_dict cur_vset_id hash idx weight total_weight voters sum_weight body _40=32 _41 _42 + STUX // vote_dict cur_vset_id hash idx weight total_weight voters sum_weight body _43 + s0 s6 s3 XCHG3 + 16 PUSHINT // vote_dict cur_vset_id hash body weight total_weight sum_weight _43 idx voters _44=16 + DICTUSETB // vote_dict cur_vset_id hash body weight total_weight sum_weight voters + s0 s3 XCHG // vote_dict cur_vset_id hash body voters total_weight sum_weight weight + ADD // vote_dict cur_vset_id hash body voters total_weight sum_weight + DUP // vote_dict cur_vset_id hash body voters total_weight sum_weight sum_weight + 3 MULCONST // vote_dict cur_vset_id hash body voters total_weight sum_weight _48 + s0 s2 XCHG // vote_dict cur_vset_id hash body voters _48 sum_weight total_weight + 1 LSHIFT# // vote_dict cur_vset_id hash body voters _48 sum_weight _50 + s1 s2 XCHG // vote_dict cur_vset_id hash body voters sum_weight _48 _50 + GREATER // vote_dict cur_vset_id hash body voters sum_weight _51 + IFJMP:<{ // vote_dict cur_vset_id hash body voters sum_weight + 2DROP + 1 2 BLKDROP2 + s0 s2 XCHG + 8 PUSHPOW2 // body hash vote_dict _53=256 + DICTUDEL // body _75 _76 + DROP // body vote_dict + SWAP // vote_dict body + }> // vote_dict cur_vset_id hash body voters sum_weight + 2SWAP + s1 s4 XCHG // vote_dict hash voters sum_weight cur_vset_id body + pack_proposal INLINECALLDICT // vote_dict hash _56 + s0 s2 XCHG + 8 PUSHPOW2 // _56 hash vote_dict _57=256 + DICTUSETB // vote_dict + PUSHNULL // vote_dict _59 }> recv_external PROC:<{ // in_msg @@ -395,29 +442,49 @@ PROGRAM{ s0 s3 XCHG // signature in_msg action vote_dict public_key cfg_dict stored_seqno cs 16 LDU // signature in_msg action vote_dict public_key cfg_dict stored_seqno idx cs OVER // signature in_msg action vote_dict public_key cfg_dict stored_seqno idx cs idx - get_validator_descr INLINECALLDICT // signature in_msg action vote_dict public_key cfg_dict stored_seqno idx cs vdescr - unpack_validator_descr INLINECALLDICT // signature in_msg action vote_dict public_key cfg_dict stored_seqno idx cs val_pubkey weight - s0 s9 XCHG // signature weight action vote_dict public_key cfg_dict stored_seqno idx cs val_pubkey in_msg - HASHSU // signature weight action vote_dict public_key cfg_dict stored_seqno idx cs val_pubkey _44 - s0 s10 s10 XCHG3 // cs weight action vote_dict public_key cfg_dict stored_seqno idx _44 signature val_pubkey - CHKSIGNU // cs weight action vote_dict public_key cfg_dict stored_seqno idx _45 + get_validator_descr INLINECALLDICT // signature in_msg action vote_dict public_key cfg_dict stored_seqno idx cs vdescr total_weight + SWAP // signature in_msg action vote_dict public_key cfg_dict stored_seqno idx cs total_weight vdescr + unpack_validator_descr INLINECALLDICT // signature in_msg action vote_dict public_key cfg_dict stored_seqno idx cs total_weight val_pubkey weight + s0 s10 XCHG // signature weight action vote_dict public_key cfg_dict stored_seqno idx cs total_weight val_pubkey in_msg + HASHSU // signature weight action vote_dict public_key cfg_dict stored_seqno idx cs total_weight val_pubkey _45 + s0 s11 s11 XCHG3 // total_weight weight action vote_dict public_key cfg_dict stored_seqno idx cs _45 signature val_pubkey + CHKSIGNU // total_weight weight action vote_dict public_key cfg_dict stored_seqno idx cs _46 34 THROWIFNOT ACCEPT - SWAP // cs weight action vote_dict public_key cfg_dict idx stored_seqno - INC // cs weight action vote_dict public_key cfg_dict idx stored_seqno - s2 s0 s3 PUSH3 - s7 PUSH // cs weight action vote_dict public_key cfg_dict idx stored_seqno cfg_dict stored_seqno public_key vote_dict + s0 s2 XCHG // total_weight weight action vote_dict public_key cfg_dict cs idx stored_seqno + INC // total_weight weight action vote_dict public_key cfg_dict cs idx stored_seqno + s3 s0 s4 PUSH3 + s8 PUSH // total_weight weight action vote_dict public_key cfg_dict cs idx stored_seqno cfg_dict stored_seqno public_key vote_dict store_data INLINECALLDICT COMMIT - s3 s5 XCHG - s7 s1 s6 XCHG3 // cfg_dict stored_seqno public_key vote_dict action cs idx weight - register_vote CALLDICT // cfg_dict stored_seqno public_key vote_dict + 34 PUSHINT // total_weight weight action vote_dict public_key cfg_dict cs idx stored_seqno _54=34 + CONFIGOPTPARAM // total_weight weight action vote_dict public_key cfg_dict cs idx stored_seqno _55 + HASHCU // total_weight weight action vote_dict public_key cfg_dict cs idx stored_seqno _56 + s5 s7 XCHG + s3 s4 XCHG + s2 s3 XCHG + s8 s9 s0 XCHG3 // stored_seqno cfg_dict public_key vote_dict action cs idx weight total_weight _56 + register_vote CALLDICT // stored_seqno cfg_dict public_key vote_dict accepted + s3 s4 s2 PUSH3 + s4 PUSH // stored_seqno cfg_dict public_key vote_dict accepted cfg_dict stored_seqno public_key vote_dict store_data INLINECALLDICT + DUP // stored_seqno cfg_dict public_key vote_dict accepted accepted + ISNULL // stored_seqno cfg_dict public_key vote_dict accepted _59 + IFNOT:<{ // stored_seqno cfg_dict public_key vote_dict accepted + 32 LDU // stored_seqno cfg_dict public_key vote_dict _60 accepted + s3 s4 XCHG + s2 s4 XCHG // stored_seqno vote_dict cfg_dict public_key _60 accepted + perform_action CALLDICT // stored_seqno vote_dict cfg_dict public_key + s3 s0 s3 XCHG3 // cfg_dict stored_seqno public_key vote_dict + store_data INLINECALLDICT + }>ELSE<{ + 5 BLKDROP // + }> }> // signature in_msg action vote_dict cs cfg_dict stored_seqno public_key s0 s6 XCHG // signature public_key action vote_dict cs cfg_dict stored_seqno in_msg - HASHSU // signature public_key action vote_dict cs cfg_dict stored_seqno _55 - s0 s7 s6 XC2PU // stored_seqno public_key action vote_dict cs cfg_dict _55 signature public_key - CHKSIGNU // stored_seqno public_key action vote_dict cs cfg_dict _56 + HASHSU // signature public_key action vote_dict cs cfg_dict stored_seqno _66 + s0 s7 s6 XC2PU // stored_seqno public_key action vote_dict cs cfg_dict _66 signature public_key + CHKSIGNU // stored_seqno public_key action vote_dict cs cfg_dict _67 34 THROWIFNOT ACCEPT s0 s5 XCHG // cfg_dict public_key action vote_dict cs stored_seqno @@ -453,16 +520,15 @@ PROGRAM{ IF:<{ // cfg_dict cs kl=32 next_vset ds 8 LDU // cfg_dict cs kl=32 next_vset tag ds 32 PLDU // cfg_dict cs kl=32 next_vset tag since - SWAP // cfg_dict cs kl=32 next_vset since tag - 17 EQINT // cfg_dict cs kl=32 next_vset since _26 - NOW // cfg_dict cs kl=32 next_vset since _26 _27 - s1 s2 XCHG // cfg_dict cs kl=32 next_vset _26 since _27 - GEQ // cfg_dict cs kl=32 next_vset _26 _28 + NOW // cfg_dict cs kl=32 next_vset tag since _25 + LEQ // cfg_dict cs kl=32 next_vset tag _26 + SWAP // cfg_dict cs kl=32 next_vset _26 tag + 18 EQINT // cfg_dict cs kl=32 next_vset _26 _28 AND // cfg_dict cs kl=32 next_vset _29 IF:<{ // cfg_dict cs kl=32 next_vset - SWAP 34 PUSHINT - s0 s4 s4 XC2PU // kl=32 cs next_vset _32=34 cfg_dict kl=32 + ROT + s4 s4 XCPU // kl=32 cs next_vset _32=34 cfg_dict kl=32 DICTISETGETOPTREF // kl=32 cs cfg_dict cur_vset s3 s1 s0 PUXCPU // kl=32 cs cur_vset _35=32 cfg_dict kl=32 DICTISETGETOPTREF // kl=32 cs _51 _52 @@ -471,18 +537,17 @@ PROGRAM{ s0 s1 s3 XCHG3 // cs _38=36 cfg_dict kl=32 DICTIDEL // cs _53 _54 DROP // cs cfg_dict + SWAP // cfg_dict cs }>ELSE<{ - s2 s3 XCHG - 2DROP // cs cfg_dict + 2DROP // cfg_dict cs }> }>ELSE<{ - s3 s4 XCHG - 3 BLKDROP // cs cfg_dict + 3 BLKDROP // cfg_dict cs }> }>ELSE<{ - s2 s3 XCHG - 2DROP // cs cfg_dict + 2DROP // cfg_dict cs }> + SWAP NEWC // cs cfg_dict _40 STREF // cs _41 SWAP // _41 cs @@ -490,4 +555,10 @@ PROGRAM{ ENDC // _43 c4 POP }> + seqno PROC:<{ + // + c4 PUSH // _0 + CTOS // _1 + 32 PLDU // _3 + }> }END>c diff --git a/submodules/ton/tonlib-src/crypto/smartcont/auto/dns-auto-code.cpp b/submodules/ton/tonlib-src/crypto/smartcont/auto/dns-auto-code.cpp new file mode 100644 index 0000000000..77cfbf739e --- /dev/null +++ b/submodules/ton/tonlib-src/crypto/smartcont/auto/dns-auto-code.cpp @@ -0,0 +1 @@ +with_tvm_code("dns-auto", "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"); diff --git a/submodules/ton/tonlib-src/crypto/smartcont/auto/dns-auto-code.fif b/submodules/ton/tonlib-src/crypto/smartcont/auto/dns-auto-code.fif new file mode 100644 index 0000000000..ad75a7db5f --- /dev/null +++ b/submodules/ton/tonlib-src/crypto/smartcont/auto/dns-auto-code.fif @@ -0,0 +1,949 @@ +// automatically generated from `smartcont/stdlib.fc` `smartcont/dns-auto-code.fc` +PROGRAM{ + DECLPROC load_data + DECLPROC load_prices + DECLPROC store_data + DECLPROC send_message + DECLPROC send_error + DECLPROC send_ok + DECLPROC housekeeping + DECLPROC calcprice_internal + DECLPROC check_owner + DECLPROC perform_ctl_op + DECLPROC recv_internal + DECLPROC recv_external + DECLPROC dnsdictlookup + 123660 DECLMETHOD dnsresolve + 87450 DECLMETHOD getexpirationx + 110574 DECLMETHOD getexpiration + 67418 DECLMETHOD getstdperiod + 109522 DECLMETHOD getppr + 108994 DECLMETHOD getppc + 113123 DECLMETHOD getppb + 113304 DECLMETHOD calcprice + 85700 DECLMETHOD calcregprice + DECLGLOBVAR query_info + load_data PROCREF:<{ + // + c4 PUSH // _1 + CTOS // cs + LDREF // _3 cs + LDDICT // _3 _5 cs + LDDICT // _3 _5 _7 cs + 30 LDU // _3 _5 _7 _10 cs + LDGRAMS // _3 _5 _7 _10 _13 cs + LDGRAMS // _3 _5 _7 _10 _13 _15 cs + LDGRAMS // _3 _5 _7 _10 _13 _15 _17 cs + 4 -ROLL // _3 _5 _7 cs _10 _13 _15 _17 + 4 TUPLE // _3 _5 _7 cs _9 + SWAP // _3 _5 _7 _9 cs + 32 LDU // _3 _5 _7 _9 _19 cs + 32 LDU // _3 _5 _7 _9 _19 _42 _41 + DROP // _3 _5 _7 _9 _19 _22 + }> + load_prices PROCREF:<{ + // + c4 PUSH // _1 + CTOS // cs + LDREF // _19 _18 + NIP // cs + LDDICT // _21 _20 + NIP // cs + LDDICT // _23 _22 + NIP // cs + 30 LDU // _9 cs + LDGRAMS // _9 _12 cs + LDGRAMS // _9 _12 _14 cs + LDGRAMS // _9 _12 _14 _31 _30 + DROP // _9 _12 _14 _16 + }> + store_data PROC:<{ + // ctl dd gc prices nhk lhk + s0 s2 XCHG // ctl dd gc lhk nhk prices + 4 UNTUPLE // ctl dd gc lhk nhk sp ppr ppc ppb + s0 s8 XCHG + NEWC // ppb dd gc lhk nhk sp ppr ppc ctl _11 + STREF // ppb dd gc lhk nhk sp ppr ppc _12 + s1 s7 XCHG // ppb ppc gc lhk nhk sp ppr dd _12 + STDICT // ppb ppc gc lhk nhk sp ppr _13 + s1 s5 XCHG // ppb ppc ppr lhk nhk sp gc _13 + STDICT // ppb ppc ppr lhk nhk sp _14 + 30 STU // ppb ppc ppr lhk nhk _16 + s0 s3 XCHG2 // ppb ppc nhk lhk _16 ppr + STGRAMS // ppb ppc nhk lhk _17 + s0 s3 XCHG2 // ppb lhk nhk _17 ppc + STGRAMS // ppb lhk nhk _18 + s0 s3 XCHG2 // nhk lhk _18 ppb + STGRAMS // nhk lhk _19 + s1 s2 XCHG // lhk nhk _19 + 32 STU // lhk _21 + 32 STU // _23 + ENDC // _24 + c4 POP + }> + send_message PROC:<{ + // addr tag query_id body grams mode + 0 PUSHINT // addr tag query_id body grams mode _7=0 + 24 PUSHINT // addr tag query_id body grams mode _7=0 _8=24 + NEWC // addr tag query_id body grams mode _7=0 _8=24 _9 + 6 STU // addr tag query_id body grams mode _7=0 _11 + s0 s7 XCHG2 // _7=0 tag query_id body grams mode _11 addr + STSLICER // _7=0 tag query_id body grams mode _12 + ROT // _7=0 tag query_id body mode _12 grams + STGRAMS // _7=0 tag query_id body mode _13 + s1 s5 XCHG // mode tag query_id body _7=0 _13 + 107 STU // mode tag query_id body _27 + s1 s3 XCHG // mode body query_id tag _27 + 32 STU // mode body query_id _29 + 64 STU // mode body msg + OVER // mode body msg body + -1 GTINT // mode body msg _33 + IF:<{ // mode body msg + 32 STU // mode msg + }>ELSE<{ + NIP // mode msg + }> + ENDC // mode _37 + SWAP // _37 mode + SENDRAWMSG + }> + send_error PROC:<{ + // error_code + query_info GETGLOB + UNTRIPLE // error_code addr query_id op + s2 s3 XCHG + 0 PUSHINT + 64 PUSHINT // addr error_code query_id op _5=0 _6=64 + send_message CALLDICT + }> + send_ok PROC:<{ + // price + 4 PUSHINT // price _1=4 + RAWRESERVE + query_info GETGLOB + UNTRIPLE // addr query_id op + 4016791929 PUSHINT // addr query_id op _7=4016791929 + -ROT + 0 PUSHINT + 7 PUSHPOW2 // addr _7=4016791929 query_id op _8=0 _9=128 + send_message CALLDICT + }> + housekeeping PROC:<{ + // ctl dd gc prices nhk lhk max_steps + NOW // ctl dd gc prices nhk lhk max_steps n + s2 PUSH // ctl dd gc prices nhk lhk max_steps n lhk + 60 ADDCONST // ctl dd gc prices nhk lhk max_steps n _10 + s4 s(-1) PUXC // ctl dd gc prices nhk lhk max_steps n nhk _10 + MAX // ctl dd gc prices nhk lhk max_steps n _11 + s1 s(-1) PUXC // ctl dd gc prices nhk lhk max_steps n n _11 + LESS // ctl dd gc prices nhk lhk max_steps n _12 + IFJMP:<{ // ctl dd gc prices nhk lhk max_steps n + 2DROP // ctl dd gc prices nhk lhk + store_data CALLDICT + }> // ctl dd gc prices nhk lhk max_steps n + s2 POP // ctl dd gc prices nhk n max_steps + s4 PUSH + 8 PUSHPOW2 // ctl dd gc prices nhk n max_steps gc _17=256 + DICTUMIN + NULLSWAPIFNOT2 // ctl dd gc prices nhk n max_steps _63 _62 _64 + s2 POP // ctl dd gc prices nhk n max_steps found? mkey + WHILE:<{ + s1 s2 XCPU // ctl dd gc prices nhk n max_steps mkey found? max_steps + AND // ctl dd gc prices nhk n max_steps mkey _19 + }>DO<{ // ctl dd gc prices nhk n max_steps mkey + s3 POP // ctl dd gc prices mkey n max_steps + s2 PUSH // ctl dd gc prices mkey n max_steps mkey + 224 RSHIFT# // ctl dd gc prices mkey n max_steps nhk + s0 s2 PUSH2 // ctl dd gc prices mkey n max_steps nhk nhk n + LESS // ctl dd gc prices mkey n max_steps nhk _24 + IF:<{ // ctl dd gc prices mkey n max_steps nhk + DROP // ctl dd gc prices mkey n max_steps + s2 PUSH // ctl dd gc prices mkey n max_steps mkey + 224 MODPOW2# // ctl dd gc prices mkey n max_steps key + s0 s6 PUSH2 + 224 PUSHINT // ctl dd gc prices mkey n max_steps key key dd _35 + DICTUGET + NULLSWAPIFNOT // ctl dd gc prices mkey n max_steps key val found? + IF:<{ // ctl dd gc prices mkey n max_steps key val + 32 PLDU // ctl dd gc prices mkey n max_steps key exp + s3 PUSH // ctl dd gc prices mkey n max_steps key exp n + LEQ // ctl dd gc prices mkey n max_steps key _40 + IF:<{ // ctl dd gc prices mkey n max_steps key + s0 s6 XCHG2 + 224 PUSHINT // ctl max_steps gc prices mkey n key dd _44 + DICTUDEL // ctl max_steps gc prices mkey n _67 _68 + DROP // ctl max_steps gc prices mkey n dd + s0 s5 XCHG // ctl dd gc prices mkey n max_steps + }>ELSE<{ + DROP // ctl dd gc prices mkey n max_steps + }> + }>ELSE<{ + 2DROP // ctl dd gc prices mkey n max_steps + }> + s2 s4 XCHG2 + 8 PUSHPOW2 // ctl dd max_steps prices n mkey gc _47=256 + DICTUDEL // ctl dd max_steps prices n _69 _70 + DROP // ctl dd max_steps prices n gc + DUP + 8 PUSHPOW2 // ctl dd max_steps prices n gc gc _50=256 + DICTUMIN + NULLSWAPIFNOT2 // ctl dd max_steps prices n gc _72 _71 _73 + s2 POP // ctl dd max_steps prices n gc found? mkey + OVER // ctl dd max_steps prices n gc found? mkey found? + IF:<{ // ctl dd max_steps prices n gc found? mkey + DUP // ctl dd max_steps prices n gc found? mkey mkey + 224 RSHIFT# // ctl dd max_steps prices n gc found? mkey _52 + }>ELSE<{ // ctl dd max_steps prices n gc found? mkey + 32 PUSHPOW2DEC // ctl dd max_steps prices n gc found? mkey _52=4294967295 + }> // ctl dd max_steps prices n gc found? mkey nhk + s0 s6 XCHG // ctl dd nhk prices n gc found? mkey max_steps + DEC // ctl dd nhk prices n gc found? mkey max_steps + }>ELSE<{ // ctl dd gc prices mkey n max_steps nhk + s5 s1 s5 XCHG3 + s0 s3 XCHG + FALSE + s0 s2 XCHG // ctl dd nhk prices n gc found? mkey max_steps + }> + s3 s6 XCHG + s3 s4 XCHG + -ROT // ctl dd gc prices nhk n max_steps found? mkey + }> // ctl dd gc prices nhk n max_steps mkey + 2DROP // ctl dd gc prices nhk n + store_data CALLDICT + }> + calcprice_internal PROCREF:<{ + // domain data ppc ppb + s0 s2 XCHG + 100 PUSHINT // domain ppb ppc data _7=100 + CDATASIZE // domain ppb ppc _24 _25 _26 + s2 POP // domain ppb ppc refs bits + s0 s4 XCHG // bits ppb ppc refs domain + SBITS // bits ppb ppc refs _9 + 1 LSHIFT# // bits ppb ppc refs _11 + 192 PUSHINT // bits ppb ppc refs _11 _16 + ADD // bits ppb ppc refs _17 + s1 s4 XCHG // refs ppb ppc bits _17 + ADD // refs ppb ppc bits + s0 s3 XCHG // bits ppb ppc refs + 2 ADDCONST // bits ppb ppc _20 + MUL // bits ppb _21 + s0 s2 XCHG // _21 ppb bits + MUL // _21 _22 + ADD // _23 + }> + check_owner PROCREF:<{ + // cat_table owner_info src_wc src_addr strict + s0 s4 XCHG // strict owner_info src_wc src_addr cat_table + ISNULL // strict owner_info src_wc src_addr _5 + s4 s(-1) PUXC // strict owner_info src_wc src_addr strict _5 + AND // strict owner_info src_wc src_addr _6 + IFJMP:<{ // strict owner_info src_wc src_addr + 4 BLKDROP // + 4000281702 PUSHINT // _7=4000281702 + }> // strict owner_info src_wc src_addr + s2 PUSH // strict owner_info src_wc src_addr owner_info + ISNULL // strict owner_info src_wc src_addr _8 + IFJMP:<{ // strict owner_info src_wc src_addr + 3 BLKDROP // strict + 4000263474 PUSHINT // strict _9=4000263474 + AND // _10 + }> // strict owner_info src_wc src_addr + s3 POP // src_addr owner_info src_wc + 3798033458 PUSHINT // src_addr owner_info src_wc ERR_BAD2=3798033458 + s0 s2 XCHG // src_addr ERR_BAD2=3798033458 src_wc owner_info + CTOS // src_addr ERR_BAD2=3798033458 src_wc sown + DUP // src_addr ERR_BAD2=3798033458 src_wc sown sown + SBITS // src_addr ERR_BAD2=3798033458 src_wc sown _15 + 283 PUSHINT // src_addr ERR_BAD2=3798033458 src_wc sown _15 _22 + LESS // src_addr ERR_BAD2=3798033458 src_wc sown _23 + IFJMP:<{ // src_addr ERR_BAD2=3798033458 src_wc sown + s2 s3 XCHG + 3 BLKDROP // ERR_BAD2=3798033458 + }> // src_addr ERR_BAD2=3798033458 src_wc sown + 19 LDU // src_addr ERR_BAD2=3798033458 src_wc _24 sown + SWAP + 327324 PUSHINT // src_addr ERR_BAD2=3798033458 src_wc sown _24 _33 + NEQ // src_addr ERR_BAD2=3798033458 src_wc sown _34 + IFJMP:<{ // src_addr ERR_BAD2=3798033458 src_wc sown + s2 s3 XCHG + 3 BLKDROP // ERR_BAD2=3798033458 + }> // src_addr ERR_BAD2=3798033458 src_wc sown + 1 2 BLKDROP2 // src_addr src_wc sown + 8 LDI // src_addr src_wc _37 sown + 256 PLDU // src_addr src_wc owner_wc owner_addr + s0 s2 XCHG // src_addr owner_addr owner_wc src_wc + NEQ // src_addr owner_addr _42 + s0 s2 XCHG // _42 owner_addr src_addr + NEQ // _42 _43 + OR // _44 + IFJMP:<{ // + 4000282478 PUSHINT // _45=4000282478 + }> // + 0 PUSHINT // _46=0 + }> + perform_ctl_op PROCREF:<{ + // op src_wc src_addr in_msg + load_data INLINECALLDICT // op src_wc src_addr in_msg ctl domdata gc prices nhk lhk + s5 PUSH // op src_wc src_addr in_msg ctl domdata gc prices nhk lhk ctl + CTOS // op src_wc src_addr in_msg ctl domdata gc prices nhk lhk cs + 8 LDI // op src_wc src_addr in_msg ctl domdata gc prices nhk lhk _13 cs + s0 s10 XCHG // op cs src_addr in_msg ctl domdata gc prices nhk lhk _13 src_wc + NEQ // op cs src_addr in_msg ctl domdata gc prices nhk lhk _16 + s0 s9 XCHG // op _16 src_addr in_msg ctl domdata gc prices nhk lhk cs + 256 LDU // op _16 src_addr in_msg ctl domdata gc prices nhk lhk _75 _74 + DROP // op _16 src_addr in_msg ctl domdata gc prices nhk lhk _17 + s0 s8 XCHG2 // op _16 lhk in_msg ctl domdata gc prices nhk _17 src_addr + NEQ // op _16 lhk in_msg ctl domdata gc prices nhk _20 + s1 s8 XCHG // op nhk lhk in_msg ctl domdata gc prices _16 _20 + OR // op nhk lhk in_msg ctl domdata gc prices _21 + IFJMP:<{ // op nhk lhk in_msg ctl domdata gc prices + 8 BLKDROP // + 4000282478 PUSHINT // _22=4000282478 + send_error CALLDICT + }> // op nhk lhk in_msg ctl domdata gc prices + s7 PUSH + 1130909810 PUSHINT // op nhk lhk in_msg ctl domdata gc prices op _24=1130909810 + EQUAL // op nhk lhk in_msg ctl domdata gc prices _25 + IFJMP:<{ // op nhk lhk in_msg ctl domdata gc prices + DROP + s6 POP // gc nhk lhk in_msg ctl domdata + s0 s2 XCHG // gc nhk lhk domdata ctl in_msg + 32 LDU // gc nhk lhk domdata ctl _30 in_msg + LDGRAMS // gc nhk lhk domdata ctl _30 _33 in_msg + LDGRAMS // gc nhk lhk domdata ctl _30 _33 _35 in_msg + LDGRAMS // gc nhk lhk domdata ctl stdper ppr ppc ppb in_msg + ENDS + 4 TUPLE // gc nhk lhk domdata ctl _40 + s0 s4 s4 XCHG3 + s0 s5 XCHG + s0 s3 XCHG // ctl domdata gc _40 nhk lhk + store_data CALLDICT + 0 PUSHINT // _42=0 + send_ok CALLDICT + }> // op nhk lhk in_msg ctl domdata gc prices + s4 POP + s4 POP // op nhk gc prices ctl domdata + s0 s5 XCHG + 1128555884 PUSHINT // domdata nhk gc prices ctl op _44=1128555884 + EQUAL // domdata nhk gc prices ctl _45 + IFJMP:<{ // domdata nhk gc prices ctl + s4 PUSH // domdata nhk gc prices ctl domdata + ISNULL // domdata nhk gc prices ctl _46 + IFNOT:<{ // domdata nhk gc prices ctl + s0 s4 XCHG + s0 s3 XCHG + 1 PUSHINT + -1 PUSHINT // ctl domdata gc prices nhk _47=1 _48=-1 + housekeeping CALLDICT + }>ELSE<{ + 5 BLKDROP // + }> + load_data INLINECALLDICT // _84 _85 _86 _87 _88 _89 + s4 s5 XCHG + 5 BLKDROP // domdata + ISNULL // _51 + IFNOTJMP:<{ // + 4000605549 PUSHINT // _52=4000605549 + send_error CALLDICT + }> // + query_info GETGLOB + UNTRIPLE // addr query_id op + 4016791929 PUSHINT // addr query_id op _58=4016791929 + -ROT + 0 PUSHINT + 160 PUSHINT // addr _58=4016791929 query_id op _59=0 _62 + send_message CALLDICT + }> // domdata nhk gc prices ctl + 5 BLKDROP // + 32 PUSHPOW2DEC // _64=4294967295 + send_error CALLDICT + }> + recv_internal PROC:<{ + // msg_value in_msg_cell in_msg + DUP // msg_value in_msg_cell in_msg in_msg + SBITS // msg_value in_msg_cell in_msg _3 + 32 LESSINT // msg_value in_msg_cell in_msg _5 + IFJMP:<{ // msg_value in_msg_cell in_msg + 3 BLKDROP // + }> // msg_value in_msg_cell in_msg + SWAP // msg_value in_msg in_msg_cell + CTOS // msg_value in_msg cs + 4 LDU // msg_value in_msg flags cs + SWAP + 1 PUSHINT // msg_value in_msg cs flags _12=1 + AND // msg_value in_msg cs _13 + IFJMP:<{ // msg_value in_msg cs + 3 BLKDROP // + }> // msg_value in_msg cs + LDMSGADDR // msg_value in_msg _327 _326 + DROP // msg_value in_msg s_addr + DUP // msg_value in_msg s_addr s_addr + REWRITESTDADDR // msg_value in_msg s_addr src_wc src_addr + s0 s3 XCHG // msg_value src_addr s_addr src_wc in_msg + 32 LDU // msg_value src_addr s_addr src_wc op in_msg + OVER // msg_value src_addr s_addr src_wc op in_msg op + IFNOTJMP:<{ // msg_value src_addr s_addr src_wc op in_msg + 6 BLKDROP // + }> // msg_value src_addr s_addr src_wc op in_msg + 0 PUSHINT // msg_value src_addr s_addr src_wc op in_msg query_id=0 + OVER // msg_value src_addr s_addr src_wc op in_msg query_id=0 in_msg + SBITS // msg_value src_addr s_addr src_wc op in_msg query_id=0 _26 + 63 GTINT // msg_value src_addr s_addr src_wc op in_msg query_id=0 _28 + IF:<{ // msg_value src_addr s_addr src_wc op in_msg query_id=0 + DROP // msg_value src_addr s_addr src_wc op in_msg + 64 LDU // msg_value src_addr s_addr src_wc op query_id in_msg + SWAP // msg_value src_addr s_addr src_wc op in_msg query_id + }> // msg_value src_addr s_addr src_wc op in_msg query_id + s4 s0 s2 XC2PU // msg_value src_addr in_msg src_wc op s_addr query_id op + TRIPLE + query_info SETGLOB + DUP + 31 PUSHPOW2 // msg_value src_addr in_msg src_wc op op _34 + AND // msg_value src_addr in_msg src_wc op _35 + IFJMP:<{ // msg_value src_addr in_msg src_wc op + 5 BLKDROP // + }> // msg_value src_addr in_msg src_wc op + DUP // msg_value src_addr in_msg src_wc op op + 24 RSHIFT# // msg_value src_addr in_msg src_wc op _37 + 67 EQINT // msg_value src_addr in_msg src_wc op _39 + IFJMP:<{ // msg_value src_addr in_msg src_wc op + s4 POP // op src_addr in_msg src_wc + -ROT // op src_wc src_addr in_msg + perform_ctl_op INLINECALLDICT + }> // msg_value src_addr in_msg src_wc op + DUP + 1919248228 PUSHINT // msg_value src_addr in_msg src_wc op op _42=1919248228 + EQUAL // msg_value src_addr in_msg src_wc op _45 + OVER + 1886547820 PUSHINT // msg_value src_addr in_msg src_wc op _45 op _46=1886547820 + EQUAL // msg_value src_addr in_msg src_wc op _45 _47 + 1 LSHIFT# // msg_value src_addr in_msg src_wc op _45 _49 + ADD // msg_value src_addr in_msg src_wc op _50 + OVER + 1970300004 PUSHINT // msg_value src_addr in_msg src_wc op _50 op _51=1970300004 + EQUAL // msg_value src_addr in_msg src_wc op _50 _52 + 2 LSHIFT# // msg_value src_addr in_msg src_wc op _50 _54 + ADD // msg_value src_addr in_msg src_wc op _55 + SWAP + 1735354211 PUSHINT // msg_value src_addr in_msg src_wc _55 op _56=1735354211 + EQUAL // msg_value src_addr in_msg src_wc _55 _57 + 3 LSHIFT# // msg_value src_addr in_msg src_wc _55 _59 + ADD // msg_value src_addr in_msg src_wc qt + DUP // msg_value src_addr in_msg src_wc qt qt + IFNOTJMP:<{ // msg_value src_addr in_msg src_wc qt + 5 BLKDROP // + 32 PUSHPOW2DEC // _61=4294967295 + send_error CALLDICT + }> // msg_value src_addr in_msg src_wc qt + NEGATE // msg_value src_addr in_msg src_wc qt + load_data INLINECALLDICT // msg_value src_addr in_msg src_wc qt ctl domdata gc prices nhk lhk + s6 PUSH // msg_value src_addr in_msg src_wc qt ctl domdata gc prices nhk lhk qt + 8 EQINT // msg_value src_addr in_msg src_wc qt ctl domdata gc prices nhk lhk _72 + IFJMP:<{ // msg_value src_addr in_msg src_wc qt ctl domdata gc prices nhk lhk + DROP + s5 POP + s5 POP + s6 POP + s6 POP // domdata gc in_msg prices nhk ctl + s0 s3 XCHG // domdata gc ctl prices nhk in_msg + 32 LDI // domdata gc ctl prices nhk _341 _340 + DROP // domdata gc ctl prices nhk max_steps + s3 s5 XCHG + s3 s4 XCHG + 1 PUSHINT + SWAP // ctl domdata gc prices nhk _77=1 max_steps + housekeeping CALLDICT + 4016791929 PUSHINT // _79=4016791929 + send_error CALLDICT + }> // msg_value src_addr in_msg src_wc qt ctl domdata gc prices nhk lhk + s0 s8 XCHG // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg + LDOPTREF // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk domain_cell in_msg + OVER // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk domain_cell in_msg domain_cell + ISNULL // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk domain_cell in_msg _88 + IF:<{ // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk domain_cell in_msg + NIP // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg + 6 LDU // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk bytes in_msg + OVER // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk bytes in_msg bytes + 0 EQINT // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk bytes in_msg fail + s0 s2 XCHG // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk fail in_msg bytes + 3 LSHIFT# // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk fail in_msg _97 + LDSLICEX // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk fail domain in_msg + }>ELSE<{ // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk domain_cell in_msg + SWAP // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain_cell + CTOS // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain + DUP // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain domain + SBITREFS // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain bits refs + SWAP // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain refs bits + -8 ADDCONST // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain refs _104 + -121 PUSHINT // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain refs _104 _107 + AND // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain refs _108 + OR // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain fail + s0 s2 XCHG // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk fail domain in_msg + }> + s2 PUSH // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk fail domain in_msg fail + IFNOT:<{ // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk fail domain in_msg + s2 POP // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain + DUP + 8 PUSHINT // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain domain _110=8 + SDCUTLAST // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain _111 + 8 PLDU // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain fail + s0 s2 XCHG // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk fail domain in_msg + }> // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk fail domain in_msg + s0 s2 XCHG // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain fail + IFJMP:<{ // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain + 12 BLKDROP // + 4000275504 PUSHINT // _114=4000275504 + send_error CALLDICT + }> // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain + NOW // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n + PUSHNULL // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n _120 + DUP // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info + 0 PUSHINT // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info _124=0 + s0 s0 s4 PUSH3 // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info key=0 zeros=0 exp=0 tail + DUP // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info key=0 zeros=0 exp=0 tail tail + SBITS // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info key=0 zeros=0 exp=0 tail _126 + 3 RSHIFTC# // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info key=0 zeros=0 exp=0 tail _128 + REPEAT:<{ // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info key zeros exp tail + PUSHNULL + s6 POP // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info key zeros exp tail + 8 LDU // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info key zeros exp _131 tail + SWAP // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info key zeros exp tail _131 + 0 EQINT // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info key zeros exp tail z + s3 s3 XCPU // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info key z exp tail zeros z + SUB // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info key z exp tail zeros + s0 s3 XCHG // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info key zeros exp tail z + IF:<{ // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info key zeros exp tail + s3 POP // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info tail zeros exp + s2 PUSH // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info tail zeros exp tail + SBITS // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info tail zeros exp _137 + s7 s(-1) PUXC // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info tail zeros exp domain _137 + SDSKIPLAST // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info tail zeros exp _138 + SHA256U // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info tail zeros exp _139 + 32 RSHIFT# // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info tail zeros exp key + s0 s12 PUSH2 + 224 PUSHINT // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info tail zeros exp key key domdata _146 + DICTUGET + NULLSWAPIFNOT // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info tail zeros exp key val found? + IF:<{ // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info tail zeros exp key val + 1 2 BLKDROP2 // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info tail zeros key val + 32 LDU // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info tail zeros key exp val + s1 s7 PUSH2 // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info tail zeros key exp val exp n + GEQ // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info tail zeros key exp val _151 + IF:<{ // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info tail zeros key exp val + LDREF // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info tail zeros key exp cat_table val + ENDS + -2 PUSHINT // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info tail zeros key exp cat_table _158=-2 + SWAP + 16 PUSHINT // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info tail zeros key exp _158=-2 cat_table _159=16 + DICTIGETREF // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info tail zeros key exp cown ok + IF:<{ // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info tail zeros key exp cown + s5 POP // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info tail zeros key exp + }>ELSE<{ + DROP // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info tail zeros key exp + }> + }>ELSE<{ + DROP // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info tail zeros key exp + }> + SWAP // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info tail zeros exp key + }>ELSE<{ + DROP // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info tail zeros exp key + }> + s0 s3 XCHG // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info key zeros exp tail + }> // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info key zeros exp tail + }> + DROP // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info key zeros exp + SWAP // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info key exp zeros + 4 GTINT // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info key exp _162 + IFJMP:<{ // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info key exp + 15 BLKDROP + 2DROP // + 4017511472 PUSHINT // _163=4017511472 + send_error CALLDICT + }> // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info key exp + s12 PUSH // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info key exp qt + 1 NEQINT // msg_value src_addr lhk src_wc qt ctl domdata gc prices nhk in_msg domain n cat_table owner_info key exp _167 + s4 PUSH + s0 s4 XCHG + s15 s1 s3 XCHG3 + s0 17 s() XCHG + SWAP // msg_value key lhk exp qt ctl domdata gc prices nhk in_msg domain n cat_table cat_table owner_info src_wc src_addr _167 + check_owner INLINECALLDICT // msg_value key lhk exp qt ctl domdata gc prices nhk in_msg domain n cat_table err + DUP // msg_value key lhk exp qt ctl domdata gc prices nhk in_msg domain n cat_table err err + IFJMP:<{ // msg_value key lhk exp qt ctl domdata gc prices nhk in_msg domain n cat_table err + s0 s14 XCHG + 14 BLKDROP // err + send_error CALLDICT + }> // msg_value key lhk exp qt ctl domdata gc prices nhk in_msg domain n cat_table err + DROP // msg_value key lhk exp qt ctl domdata gc prices nhk in_msg domain n cat_table + s9 PUSH // msg_value key lhk exp qt ctl domdata gc prices nhk in_msg domain n cat_table qt + 2 NEQINT // msg_value key lhk exp qt ctl domdata gc prices nhk in_msg domain n cat_table _173 + IF:<{ // msg_value key lhk exp qt ctl domdata gc prices nhk in_msg domain n cat_table + s0 s3 XCHG // msg_value key lhk exp qt ctl domdata gc prices nhk cat_table domain n in_msg + LDREF // msg_value key lhk exp qt ctl domdata gc prices nhk cat_table domain n _361 _360 + DROP // msg_value key lhk exp qt ctl domdata gc prices nhk cat_table domain n data + DUP // msg_value key lhk exp qt ctl domdata gc prices nhk cat_table domain n data data + DICTEMPTY // msg_value key lhk exp qt ctl domdata gc prices nhk cat_table domain n data _176 + IFNOT:<{ // msg_value key lhk exp qt ctl domdata gc prices nhk cat_table domain n data + -2 PUSHINT // msg_value key lhk exp qt ctl domdata gc prices nhk cat_table domain n data _179=-2 + OVER + 16 PUSHINT // msg_value key lhk exp qt ctl domdata gc prices nhk cat_table domain n data _179=-2 data _180=16 + DICTIGETREF // msg_value key lhk exp qt ctl domdata gc prices nhk cat_table domain n data oinfo ok + IF:<{ // msg_value key lhk exp qt ctl domdata gc prices nhk cat_table domain n data oinfo + CTOS // msg_value key lhk exp qt ctl domdata gc prices nhk cat_table domain n data cs + DUP // msg_value key lhk exp qt ctl domdata gc prices nhk cat_table domain n data cs cs + SBITS // msg_value key lhk exp qt ctl domdata gc prices nhk cat_table domain n data cs _185 + 283 PUSHINT // msg_value key lhk exp qt ctl domdata gc prices nhk cat_table domain n data cs _185 _192 + GEQ // msg_value key lhk exp qt ctl domdata gc prices nhk cat_table domain n data cs _193 + 31 THROWIFNOT + 19 PLDU // msg_value key lhk exp qt ctl domdata gc prices nhk cat_table domain n data _197 + 327324 PUSHINT // msg_value key lhk exp qt ctl domdata gc prices nhk cat_table domain n data _197 _202 + EQUAL // msg_value key lhk exp qt ctl domdata gc prices nhk cat_table domain n data _203 + 31 THROWIFNOT + }>ELSE<{ + DROP // msg_value key lhk exp qt ctl domdata gc prices nhk cat_table domain n data + }> + DUP + 16 PUSHINT // msg_value key lhk exp qt ctl domdata gc prices nhk cat_table domain n data data _208=16 + DICTIMIN + NULLSWAPIFNOT2 // msg_value key lhk exp qt ctl domdata gc prices nhk cat_table domain n data _365 _364 _366 + 2 1 BLKDROP2 // msg_value key lhk exp qt ctl domdata gc prices nhk cat_table domain n data minok + OVER + 16 PUSHINT // msg_value key lhk exp qt ctl domdata gc prices nhk cat_table domain n data minok data _213=16 + DICTIMAX + NULLSWAPIFNOT2 // msg_value key lhk exp qt ctl domdata gc prices nhk cat_table domain n data minok _368 _367 _369 + 2 1 BLKDROP2 // msg_value key lhk exp qt ctl domdata gc prices nhk cat_table domain n data minok maxok + AND // msg_value key lhk exp qt ctl domdata gc prices nhk cat_table domain n data _216 + 31 THROWIFNOT + }> // msg_value key lhk exp qt ctl domdata gc prices nhk cat_table domain n data + }>ELSE<{ // msg_value key lhk exp qt ctl domdata gc prices nhk in_msg domain n cat_table + s3 POP // msg_value key lhk exp qt ctl domdata gc prices nhk cat_table domain n + s2 PUSH // msg_value key lhk exp qt ctl domdata gc prices nhk cat_table domain n data + }> + s5 PUSH // msg_value key lhk exp qt ctl domdata gc prices nhk cat_table domain n data prices + 4 UNTUPLE // msg_value key lhk exp qt ctl domdata gc prices nhk cat_table domain n data stdper ppr ppc ppb + s3 PUSH // msg_value key lhk exp qt ctl domdata gc prices nhk cat_table domain n data stdper ppr ppc ppb stdper + IFNOTJMP:<{ // msg_value key lhk exp qt ctl domdata gc prices nhk cat_table domain n data stdper ppr ppc ppb + 15 BLKDROP + 3 BLKDROP // + 3545187910 PUSHINT // _223=3545187910 + send_error CALLDICT + }> // msg_value key lhk exp qt ctl domdata gc prices nhk cat_table domain n data stdper ppr ppc ppb + s4 PUSH + s3 s7 XCHG + -ROT // msg_value key lhk exp qt ctl domdata gc prices nhk cat_table ppr n data stdper domain data ppc ppb + calcprice_internal INLINECALLDICT // msg_value key lhk exp qt ctl domdata gc prices nhk cat_table ppr n data stdper _226 + s11 PUSH // msg_value key lhk exp qt ctl domdata gc prices nhk cat_table ppr n data stdper _226 qt + 4 NEQINT // msg_value key lhk exp qt ctl domdata gc prices nhk cat_table ppr n data stdper _226 _228 + s1 s5 XCHG // msg_value key lhk exp qt ctl domdata gc prices nhk cat_table _226 n data stdper ppr _228 + AND // msg_value key lhk exp qt ctl domdata gc prices nhk cat_table _226 n data stdper _229 + s1 s4 XCHG // msg_value key lhk exp qt ctl domdata gc prices nhk cat_table stdper n data _226 _229 + ADD // msg_value key lhk exp qt ctl domdata gc prices nhk cat_table stdper n data price + s0 s14 XCHG + 30 PUSHPOW2 // price key lhk exp qt ctl domdata gc prices nhk cat_table stdper n data msg_value _233 + SUB // price key lhk exp qt ctl domdata gc prices nhk cat_table stdper n data _234 + s14 PUSH // price key lhk exp qt ctl domdata gc prices nhk cat_table stdper n data _234 price + LESS // price key lhk exp qt ctl domdata gc prices nhk cat_table stdper n data _235 + IFJMP:<{ // price key lhk exp qt ctl domdata gc prices nhk cat_table stdper n data + 14 BLKDROP // + 3883023472 PUSHINT // _236=3883023472 + send_error CALLDICT + }> // price key lhk exp qt ctl domdata gc prices nhk cat_table stdper n data + s9 PUSH // price key lhk exp qt ctl domdata gc prices nhk cat_table stdper n data qt + 2 EQINT // price key lhk exp qt ctl domdata gc prices nhk cat_table stdper n data _243 + IFJMP:<{ // price key lhk exp qt ctl domdata gc prices nhk cat_table stdper n data + s3 POP + s8 POP // price key lhk exp n ctl domdata gc prices nhk data stdper + s7 s7 XCPU // price key lhk exp stdper ctl domdata gc prices nhk data n stdper + ADD // price key lhk exp stdper ctl domdata gc prices nhk data _244 + s8 s(-1) PUXC // price key lhk exp stdper ctl domdata gc prices nhk data exp _244 + GREATER // price key lhk exp stdper ctl domdata gc prices nhk data _245 + IFJMP:<{ // price key lhk exp stdper ctl domdata gc prices nhk data + 11 BLKDROP // + 4083511919 PUSHINT // _246=4083511919 + send_error CALLDICT + }> // price key lhk exp stdper ctl domdata gc prices nhk data + s7 s6 PUSH2 // price key lhk exp stdper ctl domdata gc prices nhk data exp stdper + ADD // price key lhk exp stdper ctl domdata gc prices nhk data _249 + NEWC // price key lhk exp stdper ctl domdata gc prices nhk data _249 _250 + 32 STU // price key lhk exp stdper ctl domdata gc prices nhk data _252 + STREF // price key lhk exp stdper ctl domdata gc prices nhk _253 + s0 s9 s4 XCPUXC + 224 PUSHINT // price key lhk exp stdper ctl nhk gc prices _253 key domdata _256 + DICTUSETB // price key lhk exp stdper ctl nhk gc prices domdata + s0 s6 XCHG // price key lhk domdata stdper ctl nhk gc prices exp + 224 LSHIFT# // price key lhk domdata stdper ctl nhk gc prices _262 + s0 s8 XCHG2 // price prices lhk domdata stdper ctl nhk gc _262 key + ADD // price prices lhk domdata stdper ctl nhk gc gckeyO + s0 s4 XCHG // price prices lhk domdata gckeyO ctl nhk gc stdper + 224 LSHIFT# // price prices lhk domdata gckeyO ctl nhk gc _268 + s4 s(-1) PUXC // price prices lhk domdata gckeyO ctl nhk gc gckeyO _268 + ADD // price prices lhk domdata gckeyO ctl nhk gc gckeyN + s4 s4 XCHG2 + 8 PUSHPOW2 // price prices lhk domdata gckeyN ctl nhk gckeyO gc _271=256 + DICTUDEL // price prices lhk domdata gckeyN ctl nhk _376 _377 + DROP // price prices lhk domdata gckeyN ctl nhk gc + NEWC // price prices lhk domdata gckeyN ctl nhk gc _274 + s0 s4 s4 XCHG3 + 8 PUSHPOW2 // price prices lhk domdata nhk ctl _274 gckeyN gc _275=256 + DICTUSETB // price prices lhk domdata nhk ctl gc + s0 s3 XCHG + s5 s5 s4 XCHG3 + 1 PUSHINT // price ctl domdata gc prices nhk lhk _277=1 + housekeeping CALLDICT + send_ok CALLDICT + }> // price key lhk exp qt ctl domdata gc prices nhk cat_table stdper n data + s9 PUSH // price key lhk exp qt ctl domdata gc prices nhk cat_table stdper n data qt + 1 EQINT // price key lhk exp qt ctl domdata gc prices nhk cat_table stdper n data _281 + IFJMP:<{ // price key lhk exp qt ctl domdata gc prices nhk cat_table stdper n data + s9 POP + s9 POP // price key lhk n data ctl domdata gc prices nhk cat_table stdper + SWAP // price key lhk n data ctl domdata gc prices nhk stdper cat_table + ISNULL // price key lhk n data ctl domdata gc prices nhk stdper _282 + IFNOTJMP:<{ // price key lhk n data ctl domdata gc prices nhk stdper + 11 BLKDROP // + 3781980773 PUSHINT // _283=3781980773 + send_error CALLDICT + }> // price key lhk n data ctl domdata gc prices nhk stdper + s1 s7 XCHG // price key lhk nhk data ctl domdata gc prices n stdper + ADD // price key lhk nhk data ctl domdata gc prices expires_at + DUP + NEWC // price key lhk nhk data ctl domdata gc prices expires_at expires_at _288 + 32 STU // price key lhk nhk data ctl domdata gc prices expires_at _290 + s1 s6 XCHG // price key lhk nhk expires_at ctl domdata gc prices data _290 + STREF // price key lhk nhk expires_at ctl domdata gc prices _291 + s0 s8 s3 XCPUXC + 224 PUSHINT // price key lhk nhk expires_at ctl prices gc _291 key domdata _294 + DICTUSETB // price key lhk nhk expires_at ctl prices gc domdata + s4 PUSH // price key lhk nhk expires_at ctl prices gc domdata expires_at + 224 LSHIFT# // price key lhk nhk expires_at ctl prices gc domdata _300 + s0 s8 XCHG2 // price domdata lhk nhk expires_at ctl prices gc _300 key + OR // price domdata lhk nhk expires_at ctl prices gc gckey + NEWC // price domdata lhk nhk expires_at ctl prices gc gckey _303 + s0 s2 XCHG + 8 PUSHPOW2 // price domdata lhk nhk expires_at ctl prices _303 gckey gc _304=256 + DICTUSETB // price domdata lhk nhk expires_at ctl prices gc + s4 s3 XCHG2 // price domdata lhk prices gc ctl nhk expires_at + MIN // price domdata lhk prices gc ctl _306 + s1 s5 XCHG + s3 s0 s4 XCHG3 + 1 PUSHINT // price ctl domdata gc prices _306 lhk _307=1 + housekeeping CALLDICT + send_ok CALLDICT + }> // price key lhk exp qt ctl domdata gc prices nhk cat_table stdper n data + s0 s3 XCHG + 3 BLKDROP // price key lhk exp qt ctl domdata gc prices nhk data + s0 s6 XCHG // price key lhk exp data ctl domdata gc prices nhk qt + 4 EQINT // price key lhk exp data ctl domdata gc prices nhk _311 + IFJMP:<{ // price key lhk exp data ctl domdata gc prices nhk + s0 s6 XCHG + NEWC // price key lhk nhk data ctl domdata gc prices exp _313 + 32 STU // price key lhk nhk data ctl domdata gc prices _315 + s1 s5 XCHG // price key lhk nhk prices ctl domdata gc data _315 + STREF // price key lhk nhk prices ctl domdata gc _316 + s7 s2 XCHG2 + 224 PUSHINT // price gc lhk nhk prices ctl _316 key domdata _319 + DICTUSETB // price gc lhk nhk prices ctl domdata + s5 s4 XCHG2 + s1 s3 XCHG + 1 PUSHINT // price ctl domdata gc prices nhk lhk _321=1 + housekeeping CALLDICT + send_ok CALLDICT + }> // price key lhk exp data ctl domdata gc prices nhk + 10 BLKDROP // + }> + recv_external PROC:<{ + // in_msg + DROP // + load_data INLINECALLDICT // _12 _13 _14 _15 _16 _17 + NIP // ctl dd gc prices lhk + IFNOTJMP:<{ // ctl dd gc prices + ACCEPT + 32 PUSHPOW2DEC // ctl dd gc prices _9=4294967295 + NOW // ctl dd gc prices _9=4294967295 _10 + store_data CALLDICT + }> // ctl dd gc prices + 4 BLKDROP // + }> + dnsdictlookup PROCREF:<{ + // domain nowtime + OVER // domain nowtime domain + SBITREFS // domain nowtime bits refs + OVER + 7 PUSHINT // domain nowtime bits refs bits _6=7 + AND // domain nowtime bits refs _7 + OR // domain nowtime bits _8 + 30 THROWIF + DUP // domain nowtime bits bits + IFNOTJMP:<{ // domain nowtime bits + 3 BLKDROP // + 0 PUSHINT // _10=0 + PUSHNULL // _10=0 _11 + OVER // _10=0 _11 _12=0 + PUSHNULL // _10=0 _11 _12=0 _13 + }> // domain nowtime bits + s2 PUSH + 8 PUSHINT // domain nowtime bits domain _15=8 + SDCUTLAST // domain nowtime bits _16 + 8 PLDU // domain nowtime bits domain_last_byte + IF:<{ // domain nowtime bits + 0 PUSHINT // domain nowtime bits _19=0 + NEWC // domain nowtime bits _19=0 _20 + s0 s4 XCHG2 // _19=0 nowtime bits _20 domain + STSLICER // _19=0 nowtime bits _21 + s1 s3 XCHG // bits nowtime _19=0 _21 + 8 STU // bits nowtime _23 + ENDC // bits nowtime _24 + CTOS // bits nowtime domain + s0 s2 XCHG // domain nowtime bits + 8 ADDCONST // domain nowtime bits + }> // domain nowtime bits + DUP // domain nowtime bits bits + 8 EQINT // domain nowtime bits _29 + IFJMP:<{ // domain nowtime bits + 3 BLKDROP // + 0 PUSHINT // _30=0 + PUSHNULL // _30=0 _31 + OVER // _30=0 _31 _32=0 + PUSHNULL // _30=0 _31 _32=0 _33 + }> // domain nowtime bits + c4 PUSH // domain nowtime bits _35 + CTOS // domain nowtime bits ds + LDREF // domain nowtime bits _87 _86 + NIP // domain nowtime bits ds + LDDICT // domain nowtime bits _89 _88 + DROP // domain nowtime bits root + PUSHNULL // domain nowtime bits root val + -1 PUSHINT // domain nowtime bits root val tail_bits=-1 + s5 PUSH // domain nowtime bits root val tail_bits=-1 tail + s0 s4 XCHG // domain nowtime tail root val tail_bits=-1 bits + 3 RSHIFT# // domain nowtime tail root val tail_bits=-1 _49 + REPEAT:<{ // domain nowtime tail root val tail_bits + s0 s3 XCHG // domain nowtime tail_bits root val tail + 8 LDU // domain nowtime tail_bits root val _50 tail + SWAP // domain nowtime tail_bits root val tail _50 + 0 EQINT // domain nowtime tail_bits root val tail _54 + IF:<{ // domain nowtime tail_bits root val tail + DUP // domain nowtime tail_bits root val tail tail + SBITS // domain nowtime tail_bits root val tail _56 + s6 s(-1) PUXC // domain nowtime tail_bits root val tail domain _56 + SDSKIPLAST // domain nowtime tail_bits root val tail _57 + SHA256U // domain nowtime tail_bits root val tail _58 + 32 RSHIFT# // domain nowtime tail_bits root val tail key + s3 PUSH + 224 PUSHINT // domain nowtime tail_bits root val tail key root _65 + DICTUGET + NULLSWAPIFNOT // domain nowtime tail_bits root val tail v found? + IF:<{ // domain nowtime tail_bits root val tail v + DUP // domain nowtime tail_bits root val tail v v + 32 PLDU // domain nowtime tail_bits root val tail v _68 + s6 PUSH // domain nowtime tail_bits root val tail v _68 nowtime + GEQ // domain nowtime tail_bits root val tail v _69 + IF:<{ // domain nowtime tail_bits root val tail v + s2 POP + s3 POP // domain nowtime tail root val + s2 PUSH // domain nowtime tail root val tail + SBITS // domain nowtime tail root val tail_bits + s0 s3 XCHG // domain nowtime tail_bits root val tail + }>ELSE<{ + DROP // domain nowtime tail_bits root val tail + }> + }>ELSE<{ + DROP // domain nowtime tail_bits root val tail + }> + }> // domain nowtime tail_bits root val tail + s0 s3 XCHG // domain nowtime tail root val tail_bits + }> + 2 2 BLKDROP2 + s2 POP // domain tail_bits val + DUP // domain tail_bits val val + ISNULL // domain tail_bits val _71 + IFJMP:<{ // domain tail_bits val + 3 BLKDROP // + 0 PUSHINT // _72=0 + PUSHNULL // _72=0 _73 + OVER // _72=0 _73 _74=0 + PUSHNULL // _72=0 _73 _74=0 _75 + }> // domain tail_bits val + 32 LDU // domain tail_bits _76 val + LDREF // domain tail_bits _76 _97 _96 + DROP // domain tail_bits _76 _79 + s2 PUSH // domain tail_bits _76 _79 tail_bits + 0 EQINT // domain tail_bits _76 _79 _82 + s4 s3 XCHG2 // _79 _82 _76 domain tail_bits + SDSKIPLAST // _79 _82 _76 _83 + s3 s3 s0 XCHG3 // _76 _79 _82 _83 + }> + dnsresolve PROC:<{ + // domain category + NOW // domain category _6 + s1 s2 XCHG // category domain _6 + dnsdictlookup INLINECALLDICT // category exp cat_table exact? pfx + s0 s3 XCHG // category pfx cat_table exact? exp + IFNOTJMP:<{ // category pfx cat_table exact? + 4 BLKDROP // + 0 PUSHINT // _8=0 + PUSHNULL // _8=0 _9 + }> // category pfx cat_table exact? + IFNOT:<{ // category pfx cat_table + -1 PUSHINT + s3 POP // category=-1 pfx cat_table + }> // category pfx cat_table + SWAP // category cat_table pfx + SBITS // category cat_table pfx_bits + s2 PUSH // category cat_table pfx_bits category + IFJMP:<{ // category cat_table pfx_bits + -ROT + 16 PUSHINT // pfx_bits category cat_table _14=16 + DICTIGETOPTREF // pfx_bits cat_found + }> // category cat_table pfx_bits + s2 POP // pfx_bits cat_table + }> + getexpirationx PROC:<{ + // domain nowtime + dnsdictlookup INLINECALLDICT // _7 _8 _9 _10 + 3 BLKDROP // exp + }> + getexpiration PROC:<{ + // domain + NOW // domain _1 + getexpirationx INLINECALLDICT // _2 + }> + getstdperiod PROC:<{ + // + load_prices INLINECALLDICT // _5 _6 _7 _8 + 3 BLKDROP // stdper + }> + getppr PROC:<{ + // + load_prices INLINECALLDICT // _5 _6 _7 _8 + s2 s3 XCHG + 3 BLKDROP // ppr + }> + getppc PROC:<{ + // + load_prices INLINECALLDICT // _5 _6 _7 _8 + s1 s3 XCHG + 3 BLKDROP // ppc + }> + getppb PROC:<{ + // + load_prices INLINECALLDICT // _5 _6 _7 _8 + s0 s3 XCHG + 3 BLKDROP // ppb + }> + calcprice PROC:<{ + // domain val + load_prices INLINECALLDICT // domain val _8 _9 _10 _11 + 2 2 BLKDROP2 // domain val ppc ppb + calcprice_internal INLINECALLDICT // _7 + }> + calcregprice PROC:<{ + // domain val + load_prices INLINECALLDICT // domain val _9 _10 _11 _12 + s3 POP // domain val ppb ppr ppc + s3 s4 XCHG + s4 s0 s4 XCHG3 // ppr domain val ppc ppb + calcprice_internal INLINECALLDICT // ppr _7 + ADD // _8 + }> +}END>c diff --git a/submodules/ton/tonlib-src/crypto/smartcont/auto/dns-manual-code.cpp b/submodules/ton/tonlib-src/crypto/smartcont/auto/dns-manual-code.cpp new file mode 100644 index 0000000000..898666a25b --- /dev/null +++ b/submodules/ton/tonlib-src/crypto/smartcont/auto/dns-manual-code.cpp @@ -0,0 +1 @@ +with_tvm_code("dns-manual", "te6ccgECGAEAAswAART/APSkE/S88sgLAQIBIAIDAgFIBAUC6vLbPAWDCNcYIPkBAdMf0z/4I6ofUyC58mNTKoBA9A5voTHyYFKUuvKiVBNG+RDyo/gAItcLBcAzmDQBdtch0/8wjoVa2zxAA+IDgyWhyEAHgED0Q44aIIBA9JZvpWwSIJQwUwe53iCTMzUBkmwh4rPmbBXwBBESAgLFBgcCASAMDQIBzwgJAAiqgl8DAgFICgsAIdAmRlj4nln+X/+gB6AGT2qkAAUXwOAAFzI9ADJ0EEz9HDyoYAAXvZznaiaGmvmOuF/8AgEgDg8AEbs3PtRNDXCx+AP5ujDCHXSSCUXwNwbeEgd7DyXiJ41yLXCweecMhQBM8WE8sHydACpgjeIMAIlF8DcG3g2zwUXwQjcAOrApjTBwHAABOhAuQgbY6bXwMhyMsGJM8WydCECSIC2zwFpRWyIMEBFUMw5jM1IpRfBXBt4WwSxwCSfzLfAtdJpvkhgRFRAAFsAAkjEB4AKAEPRqABztRNDTH9M/0//0BPQE0QE0cFmOk9s8IMcBmyDXSpPUMNCSfzPi3iLmMDETBPbTBSHBCo4sIZEx4SHAAZcx0wfUAvsA4AHACY4U1CH7BO1DAtDtHu1TVGID8QaC8gDg8i3gcCLBFJQw0g8B3m1tJMEeit4kwRSOkSWECSPbPDMClTLHAPKjkVvi3iTAC44TNAL0BFAkgBD0bjAQI4QJWfABAeAkwAyK4DAUFRYXAIQxAtMAAcABk9QB0JjTBQGqAtcYAeIg10nCD/KmIHjXItcLB/JocFMR10mpNgKY0wcBwAASoQHkMMjLBgHPFsnQUAMAIFn0qG+lIJQC9AQwkjJt4gIAKDQDgBD0WpkQI4QJQETwAQGSMDHiAGYxIsAVnDL0BBAjhAlQQvABAeAiwBaYMgKECfRzMAHgMDIgwB+TMPQE4MAgkm0B4PIsbQE="); diff --git a/submodules/ton/tonlib-src/crypto/smartcont/auto/dns-manual-code.fif b/submodules/ton/tonlib-src/crypto/smartcont/auto/dns-manual-code.fif new file mode 100644 index 0000000000..1f15c315e1 --- /dev/null +++ b/submodules/ton/tonlib-src/crypto/smartcont/auto/dns-manual-code.fif @@ -0,0 +1,477 @@ +// automatically generated from `smartcont/stdlib.fc` `smartcont/dns-manual-code.fc` +PROGRAM{ + DECLPROC pfxdict_set_ref + DECLPROC pfxdict_get_ref + DECLPROC load_data + DECLPROC store_data + DECLPROC recv_internal + 1666 DECLMETHOD after_code_upgrade + DECLPROC process_op + DECLPROC process_ops + DECLPROC recv_external + 111475 DECLMETHOD get_contract_id + 78748 DECLMETHOD get_public_key + 123660 DECLMETHOD dnsresolve + pfxdict_set_ref PROC:<{ + // dict key_len key value + NEWC // dict key_len key value _6 + STOPTREF // dict key_len key _7 + ENDC // dict key_len key _8 + CTOS // dict key_len key _9 + s1 s3 s3 XCHG3 // _9 key dict key_len + PFXDICTSET // dict _5 + 33 THROWIFNOT + }> + pfxdict_get_ref PROCREF:<{ + // dict key_len key + -ROT // key dict key_len + PFXDICTGETQ + NULLSWAPIFNOT2 // pfx val tail succ + DUP // pfx val tail succ succ + IF:<{ // pfx val tail succ + s0 s2 XCHG // pfx succ tail val + LDOPTREF // pfx succ tail _18 _17 + DROP // pfx succ tail _9 + }>ELSE<{ // pfx val tail succ + s2 POP // pfx succ tail + PUSHNULL // pfx succ tail _9 + }> // pfx succ tail res + s0 s2 XCHG // pfx res tail succ + }> + load_data PROCREF:<{ + // + c4 PUSH // _1 + CTOS // cs + 32 LDU // _4 cs + 64 LDU // _4 _7 cs + 256 LDU // _4 _7 _10 cs + LDDICT // _4 _7 _10 _13 cs + LDDICT // res res res res res cs + ENDS + }> + store_data PROC:<{ + // contract_id last_cleaned public_key root old_queries + s0 s4 XCHG + NEWC // old_queries last_cleaned public_key root contract_id _5 + 32 STU // old_queries last_cleaned public_key root _7 + s1 s3 XCHG // old_queries root public_key last_cleaned _7 + 64 STU // old_queries root public_key _9 + 256 STU // old_queries root _11 + STDICT // old_queries _12 + STDICT // _13 + ENDC // _14 + c4 POP + }> + recv_internal PROC:<{ + // msg_value in_msg_cell in_msg + 3 BLKDROP // + }> + after_code_upgrade PROC:<{ + // root ops old_code + 3 BLKDROP // + }> + process_op PROCREF:<{ + // root ops + 6 LDU // root op ops + OVER // root op ops op + 10 LESSINT // root op ops _7 + IFJMP:<{ // root op ops + OVER // root op ops op + IFNOTJMP:<{ // root op ops + NIP // root ops + }> // root op ops + OVER // root op ops op + 1 EQINT // root op ops _9 + IFJMP:<{ // root op ops + NIP // root ops + 8 LDU // root mode ops + LDREF // root mode _14 ops + s0 s2 XCHG // root ops _14 mode + SENDRAWMSG + }> // root op ops + SWAP // root ops op + 9 EQINT // root ops _18 + IFJMP:<{ // root ops + LDREF // root new_code ops + OVER // root new_code ops new_code + SETCODE + c3 PUSH // root new_code ops old_code + s0 s2 XCHG // root old_code ops new_code + CTOS // root old_code ops _25 + BLESS // root old_code ops _26 + c3 POP + s2 s(-1) s1 PU2XC // root ops root ops old_code + after_code_upgrade CALLDICT + 0 THROW + }> // root ops + 45 THROW + }> // root op ops + 0 PUSHINT // root op ops cat=0 + s2 PUSH // root op ops cat=0 op + 20 LESSINT // root op ops cat=0 _36 + IF:<{ // root op ops cat=0 + DROP // root op ops + 16 LDI // root op cat ops + SWAP // root op ops cat + }> // root op ops cat + PUSHNULL // root op ops cat name + PUSHNULL // root op ops cat name cat_table + s4 PUSH // root op ops cat name cat_table op + 30 LESSINT // root op ops cat name cat_table _45 + IF:<{ // root op ops cat name cat_table + NIP // root op ops cat cat_table + s0 s2 XCHG // root op cat_table cat ops + 1 LDU // root op cat_table cat _47 ops + SWAP // root op cat_table cat ops _47 + 1 EQINT // root op cat_table cat ops is_name_ref + IF:<{ // root op cat_table cat ops + LDREF // root op cat_table cat _52 ops + SWAP // root op cat_table cat ops _52 + CTOS // root op cat_table cat ops name + }>ELSE<{ // root op cat_table cat ops + 6 LDU // root op cat_table cat _56 ops + SWAP // root op cat_table cat ops _56 + 3 LSHIFT# // root op cat_table cat ops name_len + LDSLICEX // root op cat_table cat name ops + SWAP // root op cat_table cat ops name + }> + DUP // root op cat_table cat ops name name + SBITS // root op cat_table cat ops name _64 + 15 GTINT // root op cat_table cat ops name _66 + 38 THROWIFNOT + DUP + 8 PUSHINT // root op cat_table cat ops name name _69=8 + SDCUTLAST // root op cat_table cat ops name _70 + 8 PLDU // root op cat_table cat ops name name_last_byte + 40 THROWIF + 0 PUSHINT // root op cat_table cat ops name zeros=0 + s1 s1 PUSH2 // root op cat_table cat ops name zeros=0 cname cname + SBITS // root op cat_table cat ops name zeros=0 cname _78 + 3 RSHIFTC# // root op cat_table cat ops name zeros=0 cname _80 + REPEAT:<{ // root op cat_table cat ops name zeros cname + 8 LDU // root op cat_table cat ops name zeros c cname + SWAP // root op cat_table cat ops name zeros cname c + 0 EQINT // root op cat_table cat ops name zeros cname _86 + s1 s2 XCHG // root op cat_table cat ops name cname zeros _86 + SUB // root op cat_table cat ops name cname zeros + SWAP // root op cat_table cat ops name zeros cname + }> + DROP // root op cat_table cat ops name zeros + NEWC // root op cat_table cat ops name zeros _88 + 7 STU // root op cat_table cat ops name _90 + SWAP // root op cat_table cat ops _90 name + STSLICER // root op cat_table cat ops _91 + ENDC // root op cat_table cat ops _92 + CTOS // root op cat_table cat ops name + s0 s3 XCHG2 // root op ops cat name cat_table + }> // root op ops cat name cat_table + s4 PUSH // root op ops cat name cat_table op + 20 LESSINT // root op ops cat name cat_table _95 + IF:<{ // root op ops cat name cat_table + s5 PUSH + 10 PUSHPOW2DEC + s3 PUSH // root op ops cat name cat_table root _100=1023 name + pfxdict_get_ref INLINECALLDICT // root op ops cat name cat_table _168 _169 _170 _171 + s3 POP // root op ops cat name cat_table succ val tail + s0 s2 XCHG // root op ops cat name cat_table tail val succ + IF:<{ // root op ops cat name cat_table tail val + s2 POP // root op ops cat name val tail + SEMPTY // root op ops cat name val _103 + 35 THROWIFNOT // root op ops cat name cat_table + }>ELSE<{ + 2DROP // root op ops cat name cat_table + }> + }> // root op ops cat name cat_table + s4 PUSH // root op ops cat name cat_table op + 11 EQINT // root op ops cat name cat_table _106 + IFJMP:<{ // root op ops cat name cat_table + s4 POP // root cat_table ops cat name + s0 s2 XCHG // root cat_table name cat ops + LDOPTREF // root cat_table name cat new_value ops + s2 s4 XCHG2 + 16 PUSHINT // root ops name new_value cat cat_table _111=16 + DICTISETGETOPTREF // root ops name _174 _175 + DROP // root ops name cat_table + s2 s3 XCHG + 10 PUSHPOW2DEC + -ROT // ops root _114=1023 name cat_table + pfxdict_set_ref CALLDICT // ops root + SWAP // root ops + }> // root op ops cat name cat_table + s4 PUSH // root op ops cat name cat_table op + 12 EQINT // root op ops cat name cat_table _117 + IFJMP:<{ // root op ops cat name cat_table + s4 POP // root cat_table ops cat name + s0 s3 XCHG + 16 PUSHINT // root name ops cat cat_table _119=16 + DICTIDEL // root name ops cat_table _118 + IF:<{ // root name ops cat_table + s2 s3 XCHG + 10 PUSHPOW2DEC + s0 s4 s4 XCHG3 // ops root _122=1023 name cat_table + pfxdict_set_ref CALLDICT // ops root + SWAP // root ops + }>ELSE<{ + DROP + NIP // root ops + }> + }> // root op ops cat name cat_table + DROP + NIP // root op ops name + s2 PUSH // root op ops name op + 21 EQINT // root op ops name _125 + IFJMP:<{ // root op ops name + s2 POP // root name ops + LDOPTREF // root name new_cat_table ops + s2 s3 XCHG + 10 PUSHPOW2DEC + s4 s2 XCHG2 // ops root _130=1023 name new_cat_table + pfxdict_set_ref CALLDICT // ops root + SWAP // root ops + }> // root op ops name + s2 PUSH // root op ops name op + 22 EQINT // root op ops name _133 + IFJMP:<{ // root op ops name + s2 POP // root name ops + s0 s2 XCHG + 10 PUSHPOW2DEC // ops name root _135=1023 + PFXDICTDEL // ops _180 _181 + DROP // ops root + SWAP // root ops + }> // root op ops name + DROP + s2 POP // ops op + DUP // ops op op + 31 EQINT // ops op _138 + IFJMP:<{ // ops op + DROP // ops + LDOPTREF // new_tree_root ops + }> // ops op + 32 EQINT // ops _143 + IFJMP:<{ // ops + PUSHNULL // ops _144 + SWAP // _144 ops + }> // ops + 44 THROW + PUSHNULL // ops _147 + SWAP // _147 ops + }> + process_ops PROCREF:<{ + // root ops + FALSE // root ops stop + -ROT // stop root ops + UNTIL:<{ + process_op INLINECALLDICT // stop root ops + DUP // stop root ops ops + SDEMPTY // stop root ops _9 + IF:<{ // stop root ops + DUP // stop root ops ops + SREFS // stop root ops _10 + IF:<{ // stop root ops + LDREF // stop root _18 _17 + DROP // stop root _11 + CTOS // stop root ops + }>ELSE<{ // stop root ops + TRUE + s3 POP // stop root ops + }> + }> // stop root ops + s2 PUSH // stop root ops stop + }> // stop root ops + DROP + NIP // root + }> + recv_external PROC:<{ + // in_msg + load_data INLINECALLDICT // in_msg contract_id last_cleaned public_key root old_queries + s0 s5 XCHG + 9 PUSHPOW2 // old_queries contract_id last_cleaned public_key root in_msg _9=512 + LDSLICEX // old_queries contract_id last_cleaned public_key root signature in_msg + DUP // old_queries contract_id last_cleaned public_key root signature in_msg in_msg + HASHSU // old_queries contract_id last_cleaned public_key root signature in_msg shash + SWAP // old_queries contract_id last_cleaned public_key root signature shash in_msg + 32 LDU // old_queries contract_id last_cleaned public_key root signature shash _15 in_msg + 64 LDU // old_queries contract_id last_cleaned public_key root signature shash query_contract query_id in_msg + NOW // old_queries contract_id last_cleaned public_key root signature shash query_contract query_id in_msg _22 + 32 LSHIFT# // old_queries contract_id last_cleaned public_key root signature shash query_contract query_id in_msg bound + s2 s0 PUSH2 // old_queries contract_id last_cleaned public_key root signature shash query_contract query_id in_msg bound query_id bound + LESS // old_queries contract_id last_cleaned public_key root signature shash query_contract query_id in_msg bound _26 + 35 THROWIF + s2 s10 PUSH2 + 64 PUSHINT // old_queries contract_id last_cleaned public_key root signature shash query_contract query_id in_msg bound query_id old_queries _30=64 + DICTUGET + NULLSWAPIFNOT // old_queries contract_id last_cleaned public_key root signature shash query_contract query_id in_msg bound _84 _85 + NIP // old_queries contract_id last_cleaned public_key root signature shash query_contract query_id in_msg bound found? + 32 THROWIF + s9 s3 PUXC // old_queries contract_id last_cleaned public_key root signature shash bound query_id in_msg contract_id query_contract + EQUAL // old_queries contract_id last_cleaned public_key root signature shash bound query_id in_msg _35 + 34 THROWIFNOT + s3 s4 s6 XC2PU // old_queries contract_id last_cleaned public_key root in_msg query_id bound shash signature public_key + CHKSIGNU // old_queries contract_id last_cleaned public_key root in_msg query_id bound _38 + 35 THROWIFNOT + ACCEPT + s2 PUSH // old_queries contract_id last_cleaned public_key root in_msg query_id bound in_msg + 6 PLDU // old_queries contract_id last_cleaned public_key root in_msg query_id bound op + 51 EQINT // old_queries contract_id last_cleaned public_key root in_msg query_id bound _45 + IF:<{ // old_queries contract_id last_cleaned public_key root in_msg query_id bound + s4 POP // old_queries contract_id last_cleaned bound root in_msg query_id + SWAP + 6 PUSHINT // old_queries contract_id last_cleaned bound root query_id in_msg _47=6 + SDSKIPFIRST // old_queries contract_id last_cleaned bound root query_id in_msg + 256 LDU // old_queries contract_id last_cleaned bound root query_id _87 _86 + DROP // old_queries contract_id last_cleaned bound root query_id public_key + }>ELSE<{ // old_queries contract_id last_cleaned public_key root in_msg query_id bound + 2SWAP // old_queries contract_id last_cleaned public_key query_id bound root in_msg + process_ops INLINECALLDICT // old_queries contract_id last_cleaned public_key query_id bound root + s0 s0 s3 XCHG3 // old_queries contract_id last_cleaned bound root query_id public_key + }> + s0 s3 XCHG + 38 PUSHPOW2 // old_queries contract_id last_cleaned public_key root query_id bound _55 + SUB // old_queries contract_id last_cleaned public_key root query_id bound + NEWC // old_queries contract_id last_cleaned public_key root query_id bound _58 + s0 s0 s7 XCHG3 + 64 PUSHINT // bound contract_id last_cleaned public_key root _58 query_id old_queries _59=64 + DICTUSETB // bound contract_id last_cleaned public_key root old_queries + UNTIL:<{ + DUP + 64 PUSHINT // bound contract_id last_cleaned public_key root old_queries old_queries _66=64 + DICTUREMMIN + NULLSWAPIFNOT2 // bound contract_id last_cleaned public_key root old_queries _88 _90 _89 _91 + 1 2 BLKDROP2 // bound contract_id last_cleaned public_key root old_queries old_queries' i f + DUP // bound contract_id last_cleaned public_key root old_queries old_queries' i f f + IF:<{ // bound contract_id last_cleaned public_key root old_queries old_queries' i f + DROP // bound contract_id last_cleaned public_key root old_queries old_queries' i + s0 s7 PUSH2 // bound contract_id last_cleaned public_key root old_queries old_queries' i i bound + LESS // bound contract_id last_cleaned public_key root old_queries old_queries' i f + }> // bound contract_id last_cleaned public_key root old_queries old_queries' i f + DUP // bound contract_id last_cleaned public_key root old_queries old_queries' i f f + IF:<{ // bound contract_id last_cleaned public_key root old_queries old_queries' i f + s3 POP + s5 POP // bound contract_id last_cleaned public_key root f old_queries + SWAP // bound contract_id last_cleaned public_key root old_queries f + }>ELSE<{ + 2 1 BLKDROP2 // bound contract_id last_cleaned public_key root old_queries f + }> + NOT // bound contract_id last_cleaned public_key root old_queries _71 + }> // bound contract_id last_cleaned public_key root old_queries + 1 5 BLKDROP2 // contract_id last_cleaned public_key root old_queries + store_data CALLDICT + }> + get_contract_id PROC:<{ + // + c4 PUSH // _0 + CTOS // _1 + 32 PLDU // _3 + }> + get_public_key PROC:<{ + // + c4 PUSH // _1 + CTOS // cs + 96 LDU // _11 _10 + NIP // cs + 256 PLDU // _9 + }> + dnsresolve PROC:<{ + // subdomain category + OVER // subdomain category subdomain + SBITS // subdomain category bits + DUP // subdomain category bits bits + IFNOTJMP:<{ // subdomain category bits + 3 BLKDROP // + 0 PUSHINT // _4=0 + PUSHNULL // _4=0 _5 + }> // subdomain category bits + DUP + 7 PUSHINT // subdomain category bits bits _7=7 + AND // subdomain category bits _8 + 30 THROWIF + s2 PUSH + 8 PUSHINT // subdomain category bits subdomain _11=8 + SDCUTLAST // subdomain category bits _12 + 8 PLDU // subdomain category bits name_last_byte + IF:<{ // subdomain category bits + 0 PUSHINT // subdomain category bits _15=0 + NEWC // subdomain category bits _15=0 _16 + s0 s4 XCHG2 // _15=0 category bits _16 subdomain + STSLICER // _15=0 category bits _17 + s1 s3 XCHG // bits category _15=0 _17 + 8 STU // bits category _19 + ENDC // bits category _20 + CTOS // bits category subdomain + s0 s2 XCHG // subdomain category bits + 8 ADDCONST // subdomain category bits + }> // subdomain category bits + DUP // subdomain category bits bits + 8 EQINT // subdomain category bits _25 + IFJMP:<{ // subdomain category bits + 3 BLKDROP // + 0 PUSHINT // _26=0 + PUSHNULL // _26=0 _27 + }> // subdomain category bits + load_data INLINECALLDICT // subdomain category bits _80 _81 _82 _83 _84 + s1 s4 XCHG + 4 BLKDROP // subdomain category bits root + s3 PUSH // subdomain category bits root cname + 0 PUSHINT // subdomain category bits root cname zeros=0 + s0 s3 XCHG // subdomain category zeros=0 root cname bits + 3 RSHIFT# // subdomain category zeros=0 root cname _38 + REPEAT:<{ // subdomain category zeros root cname + 8 LDU // subdomain category zeros root c cname + SWAP // subdomain category zeros root cname c + 0 EQINT // subdomain category zeros root cname _44 + s1 s3 XCHG // subdomain category cname root zeros _44 + SUB // subdomain category cname root zeros + s0 s2 XCHG // subdomain category zeros root cname + }> + DUP // subdomain category zeros root cname pfx + PUSHNULL // subdomain category zeros root tail pfx val + UNTIL:<{ + 3 BLKDROP // subdomain category zeros root + OVER + NEWC // subdomain category zeros root zeros _51 + 7 STU // subdomain category zeros root _53 + s4 PUSH // subdomain category zeros root _53 subdomain + STSLICER // subdomain category zeros root _54 + ENDC // subdomain category zeros root _55 + CTOS // subdomain category zeros root pfxname + 10 PUSHPOW2DEC // subdomain category zeros root pfxname _58=1023 + s2 PUSH + s0 s2 XCHG // subdomain category zeros root root _58=1023 pfxname + pfxdict_get_ref INLINECALLDICT // subdomain category zeros root pfx val tail succ + s0 s5 XCHG // subdomain category succ root pfx val tail zeros + DEC // subdomain category succ root pfx val tail _61 + s1 s5 XCHG // subdomain category tail root pfx val succ _61 + XOR // subdomain category tail root pfx val zeros + DUP // subdomain category tail root pfx val zeros zeros + 1 LESSINT // subdomain category tail root pfx val zeros _64 + s1 s5 XCHG + s3 s3 s0 XCHG3 // subdomain category zeros root tail pfx val _64 + }> // subdomain category zeros root tail pfx val + s3 POP + s5 POP // pfx category zeros val tail + s2 PUSH // pfx category zeros val tail zeros + IFNOTJMP:<{ // pfx category zeros val tail + 5 BLKDROP // + 0 PUSHINT // _65=0 + PUSHNULL // _65=0 _66 + }> // pfx category zeros val tail + 1 2 BLKDROP2 // pfx category val tail + SEMPTY // pfx category val _68 + IFNOT:<{ // pfx category val + -1 PUSHINT + s2 POP // pfx category=-1 val + }> // pfx category val + s0 s2 XCHG // val category pfx + SBITS // val category _71 + -7 ADDCONST // cat_table category pfx_bits + OVER // cat_table category pfx_bits category + 0 EQINT // cat_table category pfx_bits _76 + IFJMP:<{ // cat_table category pfx_bits + NIP // cat_table pfx_bits + SWAP // pfx_bits cat_table + }> // cat_table category pfx_bits + s0 s2 XCHG + 16 PUSHINT // pfx_bits category cat_table _78=16 + DICTIGETOPTREF // pfx_bits cat_found + }> +}END>c diff --git a/submodules/ton/tonlib-src/crypto/smartcont/auto/elector-code.cpp b/submodules/ton/tonlib-src/crypto/smartcont/auto/elector-code.cpp index 90cddeac51..fafe3fa48c 100644 --- a/submodules/ton/tonlib-src/crypto/smartcont/auto/elector-code.cpp +++ b/submodules/ton/tonlib-src/crypto/smartcont/auto/elector-code.cpp @@ -1 +1 @@ -with_tvm_code("elector-code", "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"); +with_tvm_code("elector-code", "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"); diff --git a/submodules/ton/tonlib-src/crypto/smartcont/auto/elector-code.fif b/submodules/ton/tonlib-src/crypto/smartcont/auto/elector-code.fif index e37ab8d892..7aa8ac2970 100644 --- a/submodules/ton/tonlib-src/crypto/smartcont/auto/elector-code.fif +++ b/submodules/ton/tonlib-src/crypto/smartcont/auto/elector-code.fif @@ -33,6 +33,7 @@ PROGRAM{ 86535 DECLMETHOD active_election_id 87852 DECLMETHOD participates_in 123541 DECLMETHOD participant_list + 86698 DECLMETHOD participant_list_extended 130944 DECLMETHOD compute_returned_stake load_data PROC:<{ // @@ -48,8 +49,8 @@ PROGRAM{ }> store_data PROC:<{ // elect credits past_elect grams active_id active_hash - NEWC // elect credits past_elect grams active_id active_hash _6 - s1 s6 XCHG // active_hash credits past_elect grams active_id elect _6 + s0 s5 XCHG + NEWC // active_hash credits past_elect grams active_id elect _6 STDICT // active_hash credits past_elect grams active_id _7 s1 s4 XCHG // active_hash active_id past_elect grams credits _7 STDICT // active_hash active_id past_elect grams _8 @@ -76,8 +77,8 @@ PROGRAM{ }> pack_elect PROC:<{ // elect_at elect_close min_stake total_stake members failed finished - NEWC // elect_at elect_close min_stake total_stake members failed finished _7 - s1 s7 XCHG // finished elect_close min_stake total_stake members failed elect_at _7 + s0 s6 XCHG + NEWC // finished elect_close min_stake total_stake members failed elect_at _7 32 STU // finished elect_close min_stake total_stake members failed _9 s1 s5 XCHG // finished failed min_stake total_stake members elect_close _9 32 STU // finished failed min_stake total_stake members _11 @@ -129,16 +130,16 @@ PROGRAM{ return_stake PROC:<{ // addr query_id reason 4000269644 PUSHINT // addr query_id reason _3=4000269644 - 0 PUSHINT // addr query_id reason _3=4000269644 _4=0 - s3 s3 s0 XCHG3 + -ROT + 0 PUSHINT 64 PUSHINT // addr _3=4000269644 query_id reason _4=0 _5=64 send_message_back CALLDICT }> send_confirmation PROC:<{ // addr query_id comment 4084484172 PUSHINT // addr query_id comment _3=4084484172 - 1000000000 PUSHINT // addr query_id comment _3=4084484172 _4=1000000000 - s3 s3 s0 XCHG3 + -ROT + 1000000000 PUSHINT 2 PUSHINT // addr _3=4084484172 query_id comment _4=1000000000 _5=2 send_message_back CALLDICT }> @@ -246,108 +247,104 @@ PROGRAM{ return_stake CALLDICT }> // s_addr msg_value elect query_id ds src_addr validator_pubkey stake_at max_factor adnl_addr s0 s7 XCHG // s_addr msg_value adnl_addr query_id ds src_addr validator_pubkey stake_at max_factor elect - unpack_elect CALLDICT // s_addr msg_value adnl_addr query_id ds src_addr validator_pubkey stake_at max_factor _146 _147 _148 _149 _150 _151 _152 + unpack_elect CALLDICT // s_addr msg_value adnl_addr query_id ds src_addr validator_pubkey stake_at max_factor _144 _145 _146 _147 _148 _149 _150 NIP // s_addr msg_value adnl_addr query_id ds src_addr validator_pubkey stake_at max_factor elect_at elect_close min_stake total_stake members finished - s0 s5 XCHG // s_addr msg_value adnl_addr query_id ds src_addr validator_pubkey stake_at max_factor finished elect_close min_stake total_stake members elect_at - s0 DUMP // s_addr msg_value adnl_addr query_id ds src_addr validator_pubkey stake_at max_factor finished elect_close min_stake total_stake members elect_at s0 s13 XCHG - 1000000000 PUSHINT // s_addr elect_at adnl_addr query_id ds src_addr validator_pubkey stake_at max_factor finished elect_close min_stake total_stake members msg_value _73=1000000000 - SUB // s_addr elect_at adnl_addr query_id ds src_addr validator_pubkey stake_at max_factor finished elect_close min_stake total_stake members msg_value - DUP // s_addr elect_at adnl_addr query_id ds src_addr validator_pubkey stake_at max_factor finished elect_close min_stake total_stake members msg_value msg_value - 12 LSHIFT# // s_addr elect_at adnl_addr query_id ds src_addr validator_pubkey stake_at max_factor finished elect_close min_stake total_stake members msg_value _76 - s3 PUSH // s_addr elect_at adnl_addr query_id ds src_addr validator_pubkey stake_at max_factor finished elect_close min_stake total_stake members msg_value _76 total_stake - LESS // s_addr elect_at adnl_addr query_id ds src_addr validator_pubkey stake_at max_factor finished elect_close min_stake total_stake members msg_value _77 - IFJMP:<{ // s_addr elect_at adnl_addr query_id ds src_addr validator_pubkey stake_at max_factor finished elect_close min_stake total_stake members msg_value - s11 s12 XCHG - 12 BLKDROP - NIP // s_addr query_id - 2 PUSHINT // s_addr query_id _78=2 + 1000000000 PUSHINT // s_addr finished adnl_addr query_id ds src_addr validator_pubkey stake_at max_factor elect_at elect_close min_stake total_stake members msg_value _71=1000000000 + SUB // s_addr finished adnl_addr query_id ds src_addr validator_pubkey stake_at max_factor elect_at elect_close min_stake total_stake members msg_value + DUP // s_addr finished adnl_addr query_id ds src_addr validator_pubkey stake_at max_factor elect_at elect_close min_stake total_stake members msg_value msg_value + 12 LSHIFT# // s_addr finished adnl_addr query_id ds src_addr validator_pubkey stake_at max_factor elect_at elect_close min_stake total_stake members msg_value _74 + s3 PUSH // s_addr finished adnl_addr query_id ds src_addr validator_pubkey stake_at max_factor elect_at elect_close min_stake total_stake members msg_value _74 total_stake + LESS // s_addr finished adnl_addr query_id ds src_addr validator_pubkey stake_at max_factor elect_at elect_close min_stake total_stake members msg_value _75 + IFJMP:<{ // s_addr finished adnl_addr query_id ds src_addr validator_pubkey stake_at max_factor elect_at elect_close min_stake total_stake members msg_value + s11 s13 XCHG + 13 BLKDROP // s_addr query_id + 2 PUSHINT // s_addr query_id _76=2 return_stake CALLDICT - }> // s_addr elect_at adnl_addr query_id ds src_addr validator_pubkey stake_at max_factor finished elect_close min_stake total_stake members msg_value - s2 s2 XCPU // s_addr elect_at adnl_addr query_id ds src_addr validator_pubkey stake_at max_factor finished elect_close min_stake msg_value members total_stake msg_value - ADD // s_addr elect_at adnl_addr query_id ds src_addr validator_pubkey stake_at max_factor finished elect_close min_stake msg_value members total_stake - s7 s13 XCPU // s_addr elect_at adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor finished elect_close min_stake msg_value members stake_at elect_at - NEQ // s_addr elect_at adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor finished elect_close min_stake msg_value members _81 - IFJMP:<{ // s_addr elect_at adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor finished elect_close min_stake msg_value members + }> // s_addr finished adnl_addr query_id ds src_addr validator_pubkey stake_at max_factor elect_at elect_close min_stake total_stake members msg_value + s2 s2 XCPU // s_addr finished adnl_addr query_id ds src_addr validator_pubkey stake_at max_factor elect_at elect_close min_stake msg_value members total_stake msg_value + ADD // s_addr finished adnl_addr query_id ds src_addr validator_pubkey stake_at max_factor elect_at elect_close min_stake msg_value members total_stake + s7 s5 XCPU // s_addr finished adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor elect_at elect_close min_stake msg_value members stake_at elect_at + NEQ // s_addr finished adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor elect_at elect_close min_stake msg_value members _79 + IFJMP:<{ // s_addr finished adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor elect_at elect_close min_stake msg_value members s10 s12 XCHG 12 BLKDROP // s_addr query_id - 3 PUSHINT // s_addr query_id _82=3 + 3 PUSHINT // s_addr query_id _80=3 return_stake CALLDICT - }> // s_addr elect_at adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor finished elect_close min_stake msg_value members - s0 s4 XCHG // s_addr elect_at adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor members elect_close min_stake msg_value finished - IFJMP:<{ // s_addr elect_at adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor members elect_close min_stake msg_value + }> // s_addr finished adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor elect_at elect_close min_stake msg_value members + s0 s12 XCHG // s_addr members adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor elect_at elect_close min_stake msg_value finished + IFJMP:<{ // s_addr members adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor elect_at elect_close min_stake msg_value s9 s11 XCHG 11 BLKDROP // s_addr query_id - 0 PUSHINT // s_addr query_id _84=0 + 0 PUSHINT // s_addr query_id _82=0 return_stake CALLDICT - }> // s_addr elect_at adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor members elect_close min_stake msg_value - s6 s3 PUSH2 - 8 PUSHPOW2 // s_addr elect_at adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor members elect_close min_stake msg_value validator_pubkey members _88=256 + }> // s_addr members adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor elect_at elect_close min_stake msg_value + s6 s11 PUSH2 + 8 PUSHPOW2 // s_addr members adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor elect_at elect_close min_stake msg_value validator_pubkey members _86=256 DICTUGET - NULLSWAPIFNOT // s_addr elect_at adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor members elect_close min_stake msg_value mem found - DUP // s_addr elect_at adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor members elect_close min_stake msg_value mem found found - IF:<{ // s_addr elect_at adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor members elect_close min_stake msg_value mem found - DROP // s_addr elect_at adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor members elect_close min_stake msg_value mem - LDGRAMS // s_addr elect_at adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor members elect_close min_stake msg_value _90 mem - -ROT // s_addr elect_at adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor members elect_close min_stake mem msg_value _90 - ADD // s_addr elect_at adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor members elect_close min_stake mem msg_value - SWAP // s_addr elect_at adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor members elect_close min_stake msg_value mem - 64 LDU // s_addr elect_at adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor members elect_close min_stake msg_value _158 _157 - NIP // s_addr elect_at adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor members elect_close min_stake msg_value mem - 256 LDU // s_addr elect_at adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor members elect_close min_stake msg_value _160 _159 - DROP // s_addr elect_at adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor members elect_close min_stake msg_value _96 - s8 s(-1) PUXC // s_addr elect_at adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor members elect_close min_stake msg_value src_addr _96 - NEQ // s_addr elect_at adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor members elect_close min_stake msg_value found + NULLSWAPIFNOT // s_addr members adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor elect_at elect_close min_stake msg_value mem found + DUP // s_addr members adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor elect_at elect_close min_stake msg_value mem found found + IF:<{ // s_addr members adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor elect_at elect_close min_stake msg_value mem found + DROP // s_addr members adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor elect_at elect_close min_stake msg_value mem + LDGRAMS // s_addr members adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor elect_at elect_close min_stake msg_value _88 mem + -ROT // s_addr members adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor elect_at elect_close min_stake mem msg_value _88 + ADD // s_addr members adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor elect_at elect_close min_stake mem msg_value + SWAP // s_addr members adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor elect_at elect_close min_stake msg_value mem + 64 LDU // s_addr members adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor elect_at elect_close min_stake msg_value _156 _155 + NIP // s_addr members adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor elect_at elect_close min_stake msg_value mem + 256 LDU // s_addr members adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor elect_at elect_close min_stake msg_value _158 _157 + DROP // s_addr members adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor elect_at elect_close min_stake msg_value _94 + s8 s(-1) PUXC // s_addr members adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor elect_at elect_close min_stake msg_value src_addr _94 + NEQ // s_addr members adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor elect_at elect_close min_stake msg_value found }>ELSE<{ - NIP // s_addr elect_at adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor members elect_close min_stake msg_value found + NIP // s_addr members adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor elect_at elect_close min_stake msg_value found }> - IFJMP:<{ // s_addr elect_at adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor members elect_close min_stake msg_value + IFJMP:<{ // s_addr members adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor elect_at elect_close min_stake msg_value s9 s11 XCHG 11 BLKDROP // s_addr query_id - 4 PUSHINT // s_addr query_id _100=4 + 4 PUSHINT // s_addr query_id _98=4 return_stake CALLDICT - }> // s_addr elect_at adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor members elect_close min_stake msg_value - s0 s1 PUSH2 // s_addr elect_at adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor members elect_close min_stake msg_value msg_value min_stake - LESS // s_addr elect_at adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor members elect_close min_stake msg_value _102 - IFJMP:<{ // s_addr elect_at adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor members elect_close min_stake msg_value + }> // s_addr members adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor elect_at elect_close min_stake msg_value + s0 s1 PUSH2 // s_addr members adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor elect_at elect_close min_stake msg_value msg_value min_stake + LESS // s_addr members adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor elect_at elect_close min_stake msg_value _100 + IFJMP:<{ // s_addr members adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor elect_at elect_close min_stake msg_value s9 s11 XCHG 11 BLKDROP // s_addr query_id - 5 PUSHINT // s_addr query_id _103=5 + 5 PUSHINT // s_addr query_id _101=5 return_stake CALLDICT - }> // s_addr elect_at adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor members elect_close min_stake msg_value - DUP // s_addr elect_at adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor members elect_close min_stake msg_value msg_value + }> // s_addr members adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor elect_at elect_close min_stake msg_value + DUP // s_addr members adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor elect_at elect_close min_stake msg_value msg_value 44 THROWIFNOT ACCEPT - NOW // s_addr elect_at adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor members elect_close min_stake msg_value _109 - NEWC // s_addr elect_at adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor members elect_close min_stake msg_value _109 _110 - ROT // s_addr elect_at adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor members elect_close min_stake _109 _110 msg_value - STGRAMS // s_addr elect_at adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor members elect_close min_stake _109 _111 - 32 STU // s_addr elect_at adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor members elect_close min_stake _113 - s1 s4 XCHG // s_addr elect_at adnl_addr query_id ds src_addr validator_pubkey total_stake min_stake members elect_close max_factor _113 - 32 STU // s_addr elect_at adnl_addr query_id ds src_addr validator_pubkey total_stake min_stake members elect_close _115 - s1 s6 XCHG // s_addr elect_at adnl_addr query_id ds elect_close validator_pubkey total_stake min_stake members src_addr _115 - 256 STU // s_addr elect_at adnl_addr query_id ds elect_close validator_pubkey total_stake min_stake members _117 - s1 s8 XCHG // s_addr elect_at members query_id ds elect_close validator_pubkey total_stake min_stake adnl_addr _117 - 256 STU // s_addr elect_at members query_id ds elect_close validator_pubkey total_stake min_stake _119 - s0 s3 s7 XCHG3 - 8 PUSHPOW2 // s_addr elect_at total_stake query_id ds elect_close min_stake _119 validator_pubkey members _120=256 - DICTUSETB // s_addr elect_at total_stake query_id ds elect_close min_stake members - FALSE // s_addr elect_at total_stake query_id ds elect_close min_stake members _122 - s5 s7 XCHG - s3 s4 XCHG - s2 s3 XCHG - s2 s6 XCHG - FALSE // s_addr query_id ds elect_at elect_close min_stake total_stake members _122 _123 - pack_elect CALLDICT // s_addr query_id ds elect - NEWC // s_addr query_id ds elect _125 - STDICT // s_addr query_id ds _126 - SWAP // s_addr query_id _126 ds - STSLICER // s_addr query_id _127 - ENDC // s_addr query_id _128 + NOW // s_addr members adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor elect_at elect_close min_stake msg_value _107 + NEWC + ROT // s_addr members adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor elect_at elect_close min_stake _107 _108 msg_value + STGRAMS // s_addr members adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor elect_at elect_close min_stake _107 _109 + 32 STU // s_addr members adnl_addr query_id ds src_addr validator_pubkey total_stake max_factor elect_at elect_close min_stake _111 + s1 s4 XCHG // s_addr members adnl_addr query_id ds src_addr validator_pubkey total_stake min_stake elect_at elect_close max_factor _111 + 32 STU // s_addr members adnl_addr query_id ds src_addr validator_pubkey total_stake min_stake elect_at elect_close _113 + s1 s6 XCHG // s_addr members adnl_addr query_id ds elect_close validator_pubkey total_stake min_stake elect_at src_addr _113 + 256 STU // s_addr members adnl_addr query_id ds elect_close validator_pubkey total_stake min_stake elect_at _115 + s1 s8 XCHG // s_addr members elect_at query_id ds elect_close validator_pubkey total_stake min_stake adnl_addr _115 + 256 STU // s_addr members elect_at query_id ds elect_close validator_pubkey total_stake min_stake _117 + s0 s3 s8 XCHG3 + 8 PUSHPOW2 // s_addr total_stake elect_at query_id ds elect_close min_stake _117 validator_pubkey members _118=256 + DICTUSETB // s_addr total_stake elect_at query_id ds elect_close min_stake members + s4 s5 XCHG + s1 s3 s0 XCHG3 + s1 s6 XCHG + FALSE + FALSE // s_addr ds query_id elect_at elect_close min_stake total_stake members _120 _121 + pack_elect CALLDICT // s_addr ds query_id elect + NEWC // s_addr ds query_id elect _123 + STDICT // s_addr ds query_id _124 + ROT // s_addr query_id _124 ds + STSLICER // s_addr query_id _125 + ENDC // s_addr query_id _126 c4 POP DUP // s_addr query_id query_id IFJMP:<{ // s_addr query_id - 0 PUSHINT // s_addr query_id _130=0 + 0 PUSHINT // s_addr query_id _128=0 send_confirmation CALLDICT }> // s_addr query_id 2DROP // @@ -361,8 +358,7 @@ PROGRAM{ s4 PUSH 8 PUSHPOW2 // credits freeze_dict tot_stakes total recovered pubkey freeze_dict _10=256 DICTUGETNEXT - NULLSWAPIFNOT - NULLSWAPIFNOT // credits freeze_dict tot_stakes total recovered cs pubkey f + NULLSWAPIFNOT2 // credits freeze_dict tot_stakes total recovered cs pubkey f DUP // credits freeze_dict tot_stakes total recovered cs pubkey f f IF:<{ // credits freeze_dict tot_stakes total recovered cs pubkey f s0 s2 XCHG // credits freeze_dict tot_stakes total recovered f pubkey cs @@ -384,13 +380,12 @@ PROGRAM{ }> s4 s3 XCHG2 // credits freeze_dict tot_stakes pubkey recovered f total stake ADD // credits freeze_dict tot_stakes pubkey recovered f total + s0 s3 XCHG // credits freeze_dict tot_stakes total recovered f pubkey }>ELSE<{ - s4 s2 XCHG2 - DROP // credits freeze_dict tot_stakes pubkey recovered f total + s2 POP // credits freeze_dict tot_stakes total recovered f pubkey }> - SWAP // credits freeze_dict tot_stakes pubkey recovered total f - NOT // credits freeze_dict tot_stakes pubkey recovered total _32 - s1 s3 XCHG // credits freeze_dict tot_stakes total recovered pubkey _32 + SWAP // credits freeze_dict tot_stakes total recovered pubkey f + NOT // credits freeze_dict tot_stakes total recovered pubkey _32 }> // credits freeze_dict tot_stakes total recovered pubkey DROP s3 POP // credits recovered tot_stakes total @@ -407,8 +402,7 @@ PROGRAM{ s6 PUSH 8 PUSHPOW2 // credits freeze_dict tot_stakes tot_bonuses total returned_bonuses recovered pubkey freeze_dict _12=256 DICTUGETNEXT - NULLSWAPIFNOT - NULLSWAPIFNOT // credits freeze_dict tot_stakes tot_bonuses total returned_bonuses recovered cs pubkey f + NULLSWAPIFNOT2 // credits freeze_dict tot_stakes tot_bonuses total returned_bonuses recovered cs pubkey f DUP // credits freeze_dict tot_stakes tot_bonuses total returned_bonuses recovered cs pubkey f f IF:<{ // credits freeze_dict tot_stakes tot_bonuses total returned_bonuses recovered cs pubkey f s0 s2 XCHG // credits freeze_dict tot_stakes tot_bonuses total returned_bonuses recovered f pubkey cs @@ -436,13 +430,12 @@ PROGRAM{ }> s5 s3 XCHG2 // credits freeze_dict tot_stakes tot_bonuses pubkey returned_bonuses recovered f total stake ADD // credits freeze_dict tot_stakes tot_bonuses pubkey returned_bonuses recovered f total + s0 s4 XCHG // credits freeze_dict tot_stakes tot_bonuses total returned_bonuses recovered f pubkey }>ELSE<{ - s5 s2 XCHG2 - DROP // credits freeze_dict tot_stakes tot_bonuses pubkey returned_bonuses recovered f total + s2 POP // credits freeze_dict tot_stakes tot_bonuses total returned_bonuses recovered f pubkey }> - SWAP // credits freeze_dict tot_stakes tot_bonuses pubkey returned_bonuses recovered total f - NOT // credits freeze_dict tot_stakes tot_bonuses pubkey returned_bonuses recovered total _38 - s1 s4 XCHG // credits freeze_dict tot_stakes tot_bonuses total returned_bonuses recovered pubkey _38 + SWAP // credits freeze_dict tot_stakes tot_bonuses total returned_bonuses recovered pubkey f + NOT // credits freeze_dict tot_stakes tot_bonuses total returned_bonuses recovered pubkey _38 }> // credits freeze_dict tot_stakes tot_bonuses total returned_bonuses recovered pubkey DROP s5 POP // credits recovered tot_stakes tot_bonuses total returned_bonuses @@ -563,8 +556,8 @@ PROGRAM{ IFJMP:<{ // active_hash msg_value elect credits past_elect grams active_id s0 s5 XCHG // active_hash active_id elect credits past_elect grams msg_value ADD // active_hash active_id elect credits past_elect grams - 2 4 BLKSWAP - SWAP // elect credits past_elect grams active_id active_hash + s3 s5 XCHG + 2 3 BLKSWAP // elect credits past_elect grams active_id active_hash store_data CALLDICT }> // active_hash msg_value elect credits past_elect grams active_id s0 s2 PUSH2 @@ -579,8 +572,8 @@ PROGRAM{ LDGRAMS // active_hash msg_value elect credits past_elect grams active_id data hash dict total_stake bonuses fs s0 s11 XCHG // active_hash fs elect credits past_elect grams active_id data hash dict total_stake bonuses msg_value ADD // active_hash fs elect credits past_elect grams active_id data hash dict total_stake bonuses - NEWC // active_hash fs elect credits past_elect grams active_id data hash dict total_stake bonuses _44 - s1 s5 XCHG // active_hash fs elect credits past_elect grams active_id bonuses hash dict total_stake data _44 + s0 s4 XCHG + NEWC // active_hash fs elect credits past_elect grams active_id bonuses hash dict total_stake data _44 64 STU // active_hash fs elect credits past_elect grams active_id bonuses hash dict total_stake _46 s1 s3 XCHG // active_hash fs elect credits past_elect grams active_id bonuses total_stake dict hash _46 256 STU // active_hash fs elect credits past_elect grams active_id bonuses total_stake dict _48 @@ -591,9 +584,8 @@ PROGRAM{ STGRAMS // active_hash fs elect credits past_elect grams active_id _51 s0 s6 XCHG2 // active_hash active_id elect credits past_elect grams _51 fs STSLICER // active_hash active_id elect credits past_elect grams _52 - SWAP - 32 PUSHINT - s6 s3 s3 PUXC2 // active_hash active_id elect credits grams _52 active_id past_elect _53=32 + s0 s5 s2 XCPUXC + 32 PUSHINT // active_hash active_id elect credits grams _52 active_id past_elect _53=32 DICTUSETB // active_hash active_id elect credits grams past_elect }>ELSE<{ // active_hash msg_value elect credits past_elect grams active_id fs DROP // active_hash msg_value elect credits past_elect grams active_id @@ -615,9 +607,8 @@ PROGRAM{ IFJMP:<{ // op s_addr query_id src_addr DROP // op s_addr query_id 4294967294 PUSHINT // op s_addr query_id _9=4294967294 - 0 PUSHINT // op s_addr query_id _9=4294967294 _10=0 - s3 s4 XCHG - s1 s3 XCHG + s0 s1 s3 XCHG3 + 0 PUSHINT 64 PUSHINT // s_addr _9=4294967294 query_id op _10=0 _11=64 send_message_back CALLDICT }> // op s_addr query_id src_addr @@ -632,9 +623,8 @@ PROGRAM{ IFNOTJMP:<{ // op s_addr query_id ds elect credits cs 4 BLKDROP // op s_addr query_id 4294967294 PUSHINT // op s_addr query_id _27=4294967294 - 0 PUSHINT // op s_addr query_id _27=4294967294 _28=0 - s3 s4 XCHG - s1 s3 XCHG + s0 s1 s3 XCHG3 + 0 PUSHINT 64 PUSHINT // s_addr _27=4294967294 query_id op _28=0 _29=64 send_message_back CALLDICT }> // op s_addr query_id ds elect credits cs @@ -642,8 +632,8 @@ PROGRAM{ s0 s5 XCHG // credits s_addr query_id ds elect cs LDGRAMS // credits s_addr query_id ds elect amount cs ENDS - NEWC // credits s_addr query_id ds elect amount _35 - s1 s2 XCHG // credits s_addr query_id ds amount elect _35 + SWAP + NEWC // credits s_addr query_id ds amount elect _35 STDICT // credits s_addr query_id ds amount _36 s1 s5 XCHG // amount s_addr query_id ds credits _36 STDICT // amount s_addr query_id ds _37 @@ -674,8 +664,8 @@ PROGRAM{ NIP // s_addr query_id 1313042276 PUSHINT // s_addr query_id op=1313042276 3460525924 PUSHINT // s_addr query_id op=1313042276 _5=3460525924 - 0 PUSHINT // s_addr query_id op=1313042276 _5=3460525924 _6=0 - s3 s3 s0 XCHG3 + -ROT + 0 PUSHINT 64 PUSHINT // s_addr _5=3460525924 query_id op=1313042276 _6=0 _7=64 send_message_back CALLDICT }> @@ -711,6 +701,8 @@ PROGRAM{ SEMPTY // s_addr query_id code cs _25 IFNOT:<{ // s_addr query_id code cs SWAP // s_addr query_id cs code + CTOS // s_addr query_id cs _26 + BLESS // s_addr query_id cs _27 c3 POP SWAP // s_addr cs query_id after_code_upgrade CALLDICT @@ -718,7 +710,7 @@ PROGRAM{ }>ELSE<{ 4 BLKDROP // }> - TRUE // _30 + TRUE // _32 }> recv_internal PROC:<{ // msg_value in_msg_cell in_msg @@ -777,9 +769,8 @@ PROGRAM{ }>ELSE<{ // query_id s_addr op 32 PUSHPOW2DEC // query_id s_addr op _37=4294967295 }> - 0 PUSHINT // query_id s_addr op _37 _40=0 - s3 s4 XCHG - s3 s3 s0 XCHG3 + s0 s3 s3 XCHG3 + 0 PUSHINT 64 PUSHINT // s_addr _37 query_id op _40=0 _41=64 send_message_back CALLDICT }> // in_msg s_addr op query_id @@ -793,8 +784,7 @@ PROGRAM{ OR // in_msg s_addr op query_id cfg_ok _48 IFJMP:<{ // in_msg s_addr op query_id cfg_ok s2 POP // in_msg s_addr cfg_ok query_id - s2 s3 XCHG - SWAP // s_addr in_msg query_id cfg_ok + s3 s0 s0 XCHG3 // s_addr in_msg query_id cfg_ok config_set_confirmed CALLDICT }> // in_msg s_addr op query_id cfg_ok DROP @@ -804,9 +794,8 @@ PROGRAM{ AND // query_id s_addr op _53 IFNOTJMP:<{ // query_id s_addr op 32 PUSHPOW2DEC // query_id s_addr op _54=4294967295 - 0 PUSHINT // query_id s_addr op _54=4294967295 _55=0 - s3 s4 XCHG - s3 s3 s0 XCHG3 + s0 s3 s3 XCHG3 + 0 PUSHINT 64 PUSHINT // s_addr _54=4294967295 query_id op _55=0 _56=64 send_message_back CALLDICT }> // query_id s_addr op @@ -845,7 +834,7 @@ PROGRAM{ CONFIGOPTPARAM // credits members min_stake max_stake min_total_stake max_stake_factor _8 CTOS // credits members min_stake max_stake min_total_stake max_stake_factor cs 16 LDU // credits members min_stake max_stake min_total_stake max_stake_factor _13 cs - 16 LDU // credits members min_stake max_stake min_total_stake max_stake_factor _13 _258 _257 + 16 LDU // credits members min_stake max_stake min_total_stake max_stake_factor _13 _256 _255 NIP // credits members min_stake max_stake min_total_stake max_stake_factor _13 cs 16 LDU // credits members min_stake max_stake min_total_stake max_stake_factor max_validators min_validators cs ENDS @@ -858,8 +847,7 @@ PROGRAM{ s9 PUSH 8 PUSHPOW2 // credits members min_stake max_stake min_total_stake max_stake_factor max_validators min_validators n sdict pubkey members _33=256 DICTUGETNEXT - NULLSWAPIFNOT - NULLSWAPIFNOT // credits members min_stake max_stake min_total_stake max_stake_factor max_validators min_validators n sdict cs pubkey f + NULLSWAPIFNOT2 // credits members min_stake max_stake min_total_stake max_stake_factor max_validators min_validators n sdict cs pubkey f DUP // credits members min_stake max_stake min_total_stake max_stake_factor max_validators min_validators n sdict cs pubkey f f IF:<{ // credits members min_stake max_stake min_total_stake max_stake_factor max_validators min_validators n sdict cs pubkey f s0 s2 XCHG // credits members min_stake max_stake min_total_stake max_stake_factor max_validators min_validators n sdict f pubkey cs @@ -871,8 +859,8 @@ PROGRAM{ ENDS s0 s3 XCHG // credits members min_stake max_stake min_total_stake max_stake_factor max_validators min_validators n sdict f pubkey stake adnl_addr max_factor addr time NEGATE // credits members min_stake max_stake min_total_stake max_stake_factor max_validators min_validators n sdict f pubkey stake adnl_addr max_factor addr _56 - NEWC // credits members min_stake max_stake min_total_stake max_stake_factor max_validators min_validators n sdict f pubkey stake adnl_addr max_factor addr _56 _57 - s1 s5 XCHG // credits members min_stake max_stake min_total_stake max_stake_factor max_validators min_validators n sdict f pubkey _56 adnl_addr max_factor addr stake _57 + s0 s4 XCHG + NEWC // credits members min_stake max_stake min_total_stake max_stake_factor max_validators min_validators n sdict f pubkey _56 adnl_addr max_factor addr stake _57 128 STU // credits members min_stake max_stake min_total_stake max_stake_factor max_validators min_validators n sdict f pubkey _56 adnl_addr max_factor addr _59 s1 s4 XCHG // credits members min_stake max_stake min_total_stake max_stake_factor max_validators min_validators n sdict f pubkey addr adnl_addr max_factor _56 _59 32 STI // credits members min_stake max_stake min_total_stake max_stake_factor max_validators min_validators n sdict f pubkey addr adnl_addr max_factor _61 @@ -892,14 +880,12 @@ PROGRAM{ DICTSETB // credits members min_stake max_stake min_total_stake max_stake_factor max_validators min_validators n pubkey f sdict s0 s3 XCHG // credits members min_stake max_stake min_total_stake max_stake_factor max_validators min_validators sdict pubkey f n INC // credits members min_stake max_stake min_total_stake max_stake_factor max_validators min_validators sdict pubkey f n + s3 s1 s3 XCHG3 // credits members min_stake max_stake min_total_stake max_stake_factor max_validators min_validators n sdict f pubkey }>ELSE<{ - s3 s4 XCHG - 2SWAP - DROP // credits members min_stake max_stake min_total_stake max_stake_factor max_validators min_validators sdict pubkey f n + s2 POP // credits members min_stake max_stake min_total_stake max_stake_factor max_validators min_validators n sdict f pubkey }> - SWAP // credits members min_stake max_stake min_total_stake max_stake_factor max_validators min_validators sdict pubkey n f - NOT // credits members min_stake max_stake min_total_stake max_stake_factor max_validators min_validators sdict pubkey n _83 - s3 s3 s0 XCHG3 // credits members min_stake max_stake min_total_stake max_stake_factor max_validators min_validators n sdict pubkey _83 + SWAP // credits members min_stake max_stake min_total_stake max_stake_factor max_validators min_validators n sdict pubkey f + NOT // credits members min_stake max_stake min_total_stake max_stake_factor max_validators min_validators n sdict pubkey _83 }> // credits members min_stake max_stake min_total_stake max_stake_factor max_validators min_validators n sdict pubkey DROP s4 POP // credits members min_stake max_stake min_total_stake sdict max_validators min_validators n @@ -919,8 +905,7 @@ PROGRAM{ s0 s3 XCHG 416 PUSHINT // credits members min_stake max_stake min_total_stake l min_validators n sdict _101 DICTREMMIN - NULLSWAPIFNOT - NULLSWAPIFNOT // credits members min_stake max_stake min_total_stake l min_validators n sdict cs key f + NULLSWAPIFNOT2 // credits members min_stake max_stake min_total_stake l min_validators n sdict cs key f DUP // credits members min_stake max_stake min_total_stake l min_validators n sdict cs key f f IF:<{ // credits members min_stake max_stake min_total_stake l min_validators n sdict cs key f SWAP // credits members min_stake max_stake min_total_stake l min_validators n sdict cs f key @@ -928,12 +913,12 @@ PROGRAM{ s1 s9 XCPU // credits members min_stake max_stake min_total_stake l min_validators n sdict cs f key _106 max_stake MIN // credits members min_stake max_stake min_total_stake l min_validators n sdict cs f key _109 SWAP // credits members min_stake max_stake min_total_stake l min_validators n sdict cs f _109 key - 32 LDU // credits members min_stake max_stake min_total_stake l min_validators n sdict cs f _109 _284 _283 + 32 LDU // credits members min_stake max_stake min_total_stake l min_validators n sdict cs f _109 _282 _281 NIP // credits members min_stake max_stake min_total_stake l min_validators n sdict cs f _109 key 256 PLDU // credits members min_stake max_stake min_total_stake l min_validators n sdict cs f stake pubkey s0 s3 XCHG // credits members min_stake max_stake min_total_stake l min_validators n sdict pubkey f stake cs 32 LDU // credits members min_stake max_stake min_total_stake l min_validators n sdict pubkey f stake _118 cs - 256 LDU // credits members min_stake max_stake min_total_stake l min_validators n sdict pubkey f stake _118 _288 _287 + 256 LDU // credits members min_stake max_stake min_total_stake l min_validators n sdict pubkey f stake _118 _286 _285 NIP // credits members min_stake max_stake min_total_stake l min_validators n sdict pubkey f stake _118 cs 256 PLDU // credits members min_stake max_stake min_total_stake l min_validators n sdict pubkey f stake max_f adnl_addr s1 s3 s0 XCHG3 @@ -941,11 +926,10 @@ PROGRAM{ 4 TUPLE // credits members min_stake max_stake min_total_stake l min_validators n sdict f _126 s0 s5 XCHG2 // credits members min_stake max_stake min_total_stake f min_validators n sdict _126 l CONS // credits members min_stake max_stake min_total_stake f min_validators n sdict l + s0 s4 XCHG // credits members min_stake max_stake min_total_stake l min_validators n sdict f }>ELSE<{ - s6 s1 s6 XCHG3 - 2DROP // credits members min_stake max_stake min_total_stake f min_validators n sdict l + 2 1 BLKDROP2 // credits members min_stake max_stake min_total_stake l min_validators n sdict f }> - s0 s4 XCHG // credits members min_stake max_stake min_total_stake l min_validators n sdict f NOT // credits members min_stake max_stake min_total_stake l min_validators n sdict _128 s1 s4 XCHG // credits members min_stake max_stake min_total_stake sdict min_validators n l _128 }> // credits members min_stake max_stake min_total_stake sdict min_validators n l @@ -973,24 +957,22 @@ PROGRAM{ s0 s2 PUSH2 // credits members min_stake n min_total_stake l i m best_stake l1 tot_stake tot_stake best_stake GREATER // credits members min_stake n min_total_stake l i m best_stake l1 tot_stake _148 IF:<{ // credits members min_stake n min_total_stake l i m best_stake l1 tot_stake - s2 POP - s2 POP // credits members min_stake n min_total_stake l i l1 tot_stake + 2 2 BLKDROP2 // credits members min_stake n min_total_stake l i l1 tot_stake s2 PUSH // credits members min_stake n min_total_stake l i l1 best_stake m + s0 s2 XCHG // credits members min_stake n min_total_stake l i m best_stake l1 }>ELSE<{ - s1 s3 XCHG - DROP // credits members min_stake n min_total_stake l i l1 best_stake m + DROP // credits members min_stake n min_total_stake l i m best_stake l1 }> }>ELSE<{ - s3 s4 XCHG2 - DROP // credits members min_stake n min_total_stake l i l1 best_stake m + s4 POP // credits members min_stake n min_total_stake l i m best_stake l1 }> - s3 s6 PUSH2 // credits members min_stake n min_total_stake l i l1 best_stake m i n - GEQ // credits members min_stake n min_total_stake l i l1 best_stake m _149 + s3 s6 PUSH2 // credits members min_stake n min_total_stake l i m best_stake l1 i n + GEQ // credits members min_stake n min_total_stake l i m best_stake l1 _149 + s1 s3 XCHG // credits members min_stake n min_total_stake l i l1 best_stake m _149 }> // credits members min_stake n min_total_stake l i l1 best_stake m - s2 POP - s2 POP - s4 POP - s4 POP // credits members best_stake m min_total_stake l + s6 POP + s6 POP + 2DROP // credits members best_stake m min_total_stake l s2 PUSH // credits members best_stake m min_total_stake l m 0 EQINT // credits members best_stake m min_total_stake l _151 s4 s2 PUXC // credits members best_stake m _151 l best_stake min_total_stake @@ -1004,14 +986,12 @@ PROGRAM{ NEWDICT // credits _154 _155=0 _156 s1 s1 PUSH2 // credits _154 _155=0 _156 _157=0 _158=0 }> // credits members best_stake m l - DUP // credits members best_stake m l l1 - s0 DUMP // credits members best_stake m l l1 - s2 PUSH // credits members best_stake m l l1 m - DEC // credits members best_stake m l l1 _163 + s0 s1 PUSH2 // credits members best_stake m l l1 m + DEC // credits members best_stake m l l1 _161 REPEAT:<{ // credits members best_stake m l l1 CDR // credits members best_stake m l l1 }> - CAR // credits members best_stake m l _166 + CAR // credits members best_stake m l _164 0 INDEX // credits members best_stake m l m_stake 0 PUSHINT // credits members best_stake m l m_stake i=0 s0 s0 PUSH2 // credits members best_stake m l m_stake i=0 tot_stake=0 tot_weight=0 @@ -1019,110 +999,107 @@ PROGRAM{ NEWDICT // credits members best_stake m l m_stake i=0 tot_stake=0 tot_weight=0 vset frozen UNTIL:<{ s0 s6 XCHG // credits members best_stake m frozen m_stake i tot_stake tot_weight vset l - UNCONS // credits members best_stake m frozen m_stake i tot_stake tot_weight vset _183 l - SWAP // credits members best_stake m frozen m_stake i tot_stake tot_weight vset l _183 + UNCONS // credits members best_stake m frozen m_stake i tot_stake tot_weight vset _181 l + SWAP // credits members best_stake m frozen m_stake i tot_stake tot_weight vset l _181 4 UNTUPLE // credits members best_stake m frozen m_stake i tot_stake tot_weight vset l stake max_f pubkey adnl_addr s1 s13 PUSH2 - 8 PUSHPOW2 // credits members best_stake m frozen m_stake i tot_stake tot_weight vset l stake max_f pubkey adnl_addr pubkey members _188=256 + 8 PUSHPOW2 // credits members best_stake m frozen m_stake i tot_stake tot_weight vset l stake max_f pubkey adnl_addr pubkey members _186=256 DICTUGET NULLSWAPIFNOT // credits members best_stake m frozen m_stake i tot_stake tot_weight vset l stake max_f pubkey adnl_addr val f 61 THROWIFNOT - LDGRAMS // credits members best_stake m frozen m_stake i tot_stake tot_weight vset l stake max_f pubkey adnl_addr _300 _299 + LDGRAMS // credits members best_stake m frozen m_stake i tot_stake tot_weight vset l stake max_f pubkey adnl_addr _298 _297 NIP // credits members best_stake m frozen m_stake i tot_stake tot_weight vset l stake max_f pubkey adnl_addr val - 64 LDU // credits members best_stake m frozen m_stake i tot_stake tot_weight vset l stake max_f pubkey adnl_addr _302 _301 + 64 LDU // credits members best_stake m frozen m_stake i tot_stake tot_weight vset l stake max_f pubkey adnl_addr _300 _299 NIP // credits members best_stake m frozen m_stake i tot_stake tot_weight vset l stake max_f pubkey adnl_addr val 256 PLDU // credits members best_stake m frozen m_stake i tot_stake tot_weight vset l stake max_f pubkey adnl_addr src_addr s9 s12 PUSH2 // credits members best_stake m frozen m_stake i tot_stake tot_weight vset l stake max_f pubkey adnl_addr src_addr i m - LESS // credits members best_stake m frozen m_stake i tot_stake tot_weight vset l stake max_f pubkey adnl_addr src_addr _202 + LESS // credits members best_stake m frozen m_stake i tot_stake tot_weight vset l stake max_f pubkey adnl_addr src_addr _200 IF:<{ // credits members best_stake m frozen m_stake i tot_stake tot_weight vset l stake max_f pubkey adnl_addr src_addr s3 s10 XCPU // credits members best_stake m frozen m_stake i tot_stake tot_weight vset l stake src_addr pubkey adnl_addr max_f m_stake - MUL // credits members best_stake m frozen m_stake i tot_stake tot_weight vset l stake src_addr pubkey adnl_addr _204 - 16 RSHIFT# // credits members best_stake m frozen m_stake i tot_stake tot_weight vset l stake src_addr pubkey adnl_addr _206 - s4 s(-1) PUXC // credits members best_stake m frozen m_stake i tot_stake tot_weight vset l stake src_addr pubkey adnl_addr stake _206 + MUL // credits members best_stake m frozen m_stake i tot_stake tot_weight vset l stake src_addr pubkey adnl_addr _202 + 16 RSHIFT# // credits members best_stake m frozen m_stake i tot_stake tot_weight vset l stake src_addr pubkey adnl_addr _204 + s4 s(-1) PUXC // credits members best_stake m frozen m_stake i tot_stake tot_weight vset l stake src_addr pubkey adnl_addr stake _204 MIN // credits members best_stake m frozen m_stake i tot_stake tot_weight vset l stake src_addr pubkey adnl_addr true_stake s4 s4 XCPU // credits members best_stake m frozen m_stake i tot_stake tot_weight vset l true_stake src_addr pubkey adnl_addr stake true_stake SUB // credits members best_stake m frozen m_stake i tot_stake tot_weight vset l true_stake src_addr pubkey adnl_addr stake s4 PUSH // credits members best_stake m frozen m_stake i tot_stake tot_weight vset l true_stake src_addr pubkey adnl_addr stake true_stake - 60 LSHIFT# // credits members best_stake m frozen m_stake i tot_stake tot_weight vset l true_stake src_addr pubkey adnl_addr stake _211 - s14 PUSH // credits members best_stake m frozen m_stake i tot_stake tot_weight vset l true_stake src_addr pubkey adnl_addr stake _211 best_stake + 60 LSHIFT# // credits members best_stake m frozen m_stake i tot_stake tot_weight vset l true_stake src_addr pubkey adnl_addr stake _209 + s14 PUSH // credits members best_stake m frozen m_stake i tot_stake tot_weight vset l true_stake src_addr pubkey adnl_addr stake _209 best_stake DIV // credits members best_stake m frozen m_stake i tot_stake tot_weight vset l true_stake src_addr pubkey adnl_addr stake weight s9 s5 XCPU // credits members best_stake m frozen m_stake i weight tot_weight vset l true_stake src_addr pubkey adnl_addr stake tot_stake true_stake ADD // credits members best_stake m frozen m_stake i weight tot_weight vset l true_stake src_addr pubkey adnl_addr stake tot_stake s8 s9 XCPU // credits members best_stake m frozen m_stake i weight tot_stake vset l true_stake src_addr pubkey adnl_addr stake tot_weight weight ADD // credits members best_stake m frozen m_stake i weight tot_stake vset l true_stake src_addr pubkey adnl_addr stake tot_weight - 2390828938 PUSHINT // credits members best_stake m frozen m_stake i weight tot_stake vset l true_stake src_addr pubkey adnl_addr stake tot_weight _216=2390828938 - s3 PUSH // credits members best_stake m frozen m_stake i weight tot_stake vset l true_stake src_addr pubkey adnl_addr stake tot_weight _216=2390828938 adnl_addr - IF:<{ // credits members best_stake m frozen m_stake i weight tot_stake vset l true_stake src_addr pubkey adnl_addr stake tot_weight _216=2390828938 - 115 PUSHINT // credits members best_stake m frozen m_stake i weight tot_stake vset l true_stake src_addr pubkey adnl_addr stake tot_weight _216=2390828938 _217=115 - }>ELSE<{ // credits members best_stake m frozen m_stake i weight tot_stake vset l true_stake src_addr pubkey adnl_addr stake tot_weight _216=2390828938 - 83 PUSHINT // credits members best_stake m frozen m_stake i weight tot_stake vset l true_stake src_addr pubkey adnl_addr stake tot_weight _216=2390828938 _217=83 + 2390828938 PUSHINT // credits members best_stake m frozen m_stake i weight tot_stake vset l true_stake src_addr pubkey adnl_addr stake tot_weight _214=2390828938 + s3 PUSH // credits members best_stake m frozen m_stake i weight tot_stake vset l true_stake src_addr pubkey adnl_addr stake tot_weight _214=2390828938 adnl_addr + IF:<{ // credits members best_stake m frozen m_stake i weight tot_stake vset l true_stake src_addr pubkey adnl_addr stake tot_weight _214=2390828938 + 115 PUSHINT // credits members best_stake m frozen m_stake i weight tot_stake vset l true_stake src_addr pubkey adnl_addr stake tot_weight _214=2390828938 _215=115 + }>ELSE<{ // credits members best_stake m frozen m_stake i weight tot_stake vset l true_stake src_addr pubkey adnl_addr stake tot_weight _214=2390828938 + 83 PUSHINT // credits members best_stake m frozen m_stake i weight tot_stake vset l true_stake src_addr pubkey adnl_addr stake tot_weight _214=2390828938 _215=83 }> - NEWC // credits members best_stake m frozen m_stake i weight tot_stake vset l true_stake src_addr pubkey adnl_addr stake tot_weight _216=2390828938 _217 _220 - 8 STU // credits members best_stake m frozen m_stake i weight tot_stake vset l true_stake src_addr pubkey adnl_addr stake tot_weight _216=2390828938 _222 - 32 STU // credits members best_stake m frozen m_stake i weight tot_stake vset l true_stake src_addr pubkey adnl_addr stake tot_weight _224 - s4 s(-1) PUXC // credits members best_stake m frozen m_stake i weight tot_stake vset l true_stake src_addr pubkey adnl_addr stake tot_weight pubkey _224 - 256 STU // credits members best_stake m frozen m_stake i weight tot_stake vset l true_stake src_addr pubkey adnl_addr stake tot_weight _226 - s10 s(-1) PUXC // credits members best_stake m frozen m_stake i weight tot_stake vset l true_stake src_addr pubkey adnl_addr stake tot_weight weight _226 + NEWC // credits members best_stake m frozen m_stake i weight tot_stake vset l true_stake src_addr pubkey adnl_addr stake tot_weight _214=2390828938 _215 _218 + 8 STU // credits members best_stake m frozen m_stake i weight tot_stake vset l true_stake src_addr pubkey adnl_addr stake tot_weight _214=2390828938 _220 + 32 STU // credits members best_stake m frozen m_stake i weight tot_stake vset l true_stake src_addr pubkey adnl_addr stake tot_weight _222 + s4 s(-1) PUXC // credits members best_stake m frozen m_stake i weight tot_stake vset l true_stake src_addr pubkey adnl_addr stake tot_weight pubkey _222 + 256 STU // credits members best_stake m frozen m_stake i weight tot_stake vset l true_stake src_addr pubkey adnl_addr stake tot_weight _224 + s10 s(-1) PUXC // credits members best_stake m frozen m_stake i weight tot_stake vset l true_stake src_addr pubkey adnl_addr stake tot_weight weight _224 64 STU // credits members best_stake m frozen m_stake i weight tot_stake vset l true_stake src_addr pubkey adnl_addr stake tot_weight vinfo s3 PUSH // credits members best_stake m frozen m_stake i weight tot_stake vset l true_stake src_addr pubkey adnl_addr stake tot_weight vinfo adnl_addr IF:<{ // credits members best_stake m frozen m_stake i weight tot_stake vset l true_stake src_addr pubkey adnl_addr stake tot_weight vinfo s1 s3 XCHG // credits members best_stake m frozen m_stake i weight tot_stake vset l true_stake src_addr pubkey tot_weight stake adnl_addr vinfo 256 STU // credits members best_stake m frozen m_stake i weight tot_stake vset l true_stake src_addr pubkey tot_weight stake vinfo + s0 s2 XCHG // credits members best_stake m frozen m_stake i weight tot_stake vset l true_stake src_addr pubkey vinfo stake tot_weight }>ELSE<{ - s0 s3 XCHG2 - DROP // credits members best_stake m frozen m_stake i weight tot_stake vset l true_stake src_addr pubkey tot_weight stake vinfo + s3 POP // credits members best_stake m frozen m_stake i weight tot_stake vset l true_stake src_addr pubkey vinfo stake tot_weight }> - SWAP - 16 PUSHINT - s11 s8 s8 PUXC2 // credits members best_stake m frozen m_stake i weight tot_stake stake l true_stake src_addr pubkey tot_weight vinfo i vset _233=16 - DICTUSETB // credits members best_stake m frozen m_stake i weight tot_stake stake l true_stake src_addr pubkey tot_weight vset - FALSE // credits members best_stake m frozen m_stake i weight tot_stake stake l true_stake src_addr pubkey tot_weight vset _236 + s2 s10 s7 XCPUXC + 16 PUSHINT // credits members best_stake m frozen m_stake i weight tot_stake tot_weight l true_stake src_addr pubkey stake vinfo i vset _231=16 + DICTUSETB // credits members best_stake m frozen m_stake i weight tot_stake tot_weight l true_stake src_addr pubkey stake vset + FALSE // credits members best_stake m frozen m_stake i weight tot_stake tot_weight l true_stake src_addr pubkey stake vset _234 s4 PUSH - NEWC // credits members best_stake m frozen m_stake i weight tot_stake stake l true_stake src_addr pubkey tot_weight vset _236 src_addr _237 - 256 STU // credits members best_stake m frozen m_stake i weight tot_stake stake l true_stake src_addr pubkey tot_weight vset _236 _239 - s1 s10 XCHG // credits members best_stake m frozen m_stake i _236 tot_stake stake l true_stake src_addr pubkey tot_weight vset weight _239 - 64 STU // credits members best_stake m frozen m_stake i _236 tot_stake stake l true_stake src_addr pubkey tot_weight vset _241 - s0 s5 XCHG2 // credits members best_stake m frozen m_stake i _236 tot_stake stake l vset src_addr pubkey tot_weight _241 true_stake - STGRAMS // credits members best_stake m frozen m_stake i _236 tot_stake stake l vset src_addr pubkey tot_weight _242 - s1 s8 XCHG // credits members best_stake m frozen m_stake i tot_weight tot_stake stake l vset src_addr pubkey _236 _242 - 1 STI // credits members best_stake m frozen m_stake i tot_weight tot_stake stake l vset src_addr pubkey _244 + NEWC // credits members best_stake m frozen m_stake i weight tot_stake tot_weight l true_stake src_addr pubkey stake vset _234 src_addr _235 + 256 STU // credits members best_stake m frozen m_stake i weight tot_stake tot_weight l true_stake src_addr pubkey stake vset _234 _237 + s1 s10 XCHG // credits members best_stake m frozen m_stake i _234 tot_stake tot_weight l true_stake src_addr pubkey stake vset weight _237 + 64 STU // credits members best_stake m frozen m_stake i _234 tot_stake tot_weight l true_stake src_addr pubkey stake vset _239 + s0 s5 XCHG2 // credits members best_stake m frozen m_stake i _234 tot_stake tot_weight l vset src_addr pubkey stake _239 true_stake + STGRAMS // credits members best_stake m frozen m_stake i _234 tot_stake tot_weight l vset src_addr pubkey stake _240 + s1 s8 XCHG // credits members best_stake m frozen m_stake i stake tot_stake tot_weight l vset src_addr pubkey _234 _240 + 1 STI // credits members best_stake m frozen m_stake i stake tot_stake tot_weight l vset src_addr pubkey _242 s0 s1 s10 XCHG3 - 8 PUSHPOW2 // credits members best_stake m src_addr m_stake i tot_weight tot_stake stake l vset _244 pubkey frozen _245=256 - DICTUSETB // credits members best_stake m src_addr m_stake i tot_weight tot_stake stake l vset frozen + 8 PUSHPOW2 // credits members best_stake m src_addr m_stake i stake tot_stake tot_weight l vset _242 pubkey frozen _243=256 + DICTUSETB // credits members best_stake m src_addr m_stake i stake tot_stake tot_weight l vset frozen + s0 s8 XCHG + s4 s5 XCHG + s1 s3 XCHG + s1 s4 XCHG // credits members best_stake m frozen m_stake i tot_stake tot_weight vset l stake src_addr }>ELSE<{ - s0 s11 XCHG - s7 s8 XCHG - s4 s6 XCHG s0 s3 XCHG - 3 BLKDROP // credits members best_stake m src_addr m_stake i tot_weight tot_stake stake l vset frozen + 3 BLKDROP // credits members best_stake m frozen m_stake i tot_stake tot_weight vset l stake src_addr }> - s3 PUSH // credits members best_stake m src_addr m_stake i tot_weight tot_stake stake l vset frozen stake - IF:<{ // credits members best_stake m src_addr m_stake i tot_weight tot_stake stake l vset frozen - s12 s8 s3 XCHG3 // l members best_stake m vset m_stake i tot_weight tot_stake frozen credits src_addr stake - ~credit_to CALLDICT // l members best_stake m vset m_stake i tot_weight tot_stake frozen credits + OVER // credits members best_stake m frozen m_stake i tot_stake tot_weight vset l stake src_addr stake + IF:<{ // credits members best_stake m frozen m_stake i tot_stake tot_weight vset l stake src_addr + s12 s0 s0 XCHG3 // l members best_stake m frozen m_stake i tot_stake tot_weight vset credits src_addr stake + ~credit_to CALLDICT // l members best_stake m frozen m_stake i tot_stake tot_weight vset credits + s0 s10 XCHG // credits members best_stake m frozen m_stake i tot_stake tot_weight vset l }>ELSE<{ - s12 s8 s3 XCHG3 - 2DROP // l members best_stake m vset m_stake i tot_weight tot_stake frozen credits + 2DROP // credits members best_stake m frozen m_stake i tot_stake tot_weight vset l }> - s0 s4 XCHG // l members best_stake m vset m_stake credits tot_weight tot_stake frozen i - INC // l members best_stake m vset m_stake credits tot_weight tot_stake frozen i - s10 PUSH // l members best_stake m vset m_stake credits tot_weight tot_stake frozen i l - ISNULL // l members best_stake m vset m_stake credits tot_weight tot_stake frozen i _251 - s5 s11 XCHG - s5 s7 XCHG + s0 s4 XCHG // credits members best_stake m frozen m_stake l tot_stake tot_weight vset i + INC // credits members best_stake m frozen m_stake l tot_stake tot_weight vset i + s4 PUSH // credits members best_stake m frozen m_stake l tot_stake tot_weight vset i l + ISNULL // credits members best_stake m frozen m_stake l tot_stake tot_weight vset i _249 s1 s5 XCHG - s3 s4 XCHG - s1 s2 XCHG // credits members best_stake m l m_stake i tot_stake tot_weight vset frozen _251 + s1 s7 XCHG // credits members best_stake m l m_stake i tot_stake tot_weight vset frozen _249 }> // credits members best_stake m l m_stake i tot_stake tot_weight vset frozen s4 POP s4 POP s4 POP s6 POP // credits tot_stake best_stake m tot_weight vset frozen s5 s4 PUXC // credits tot_stake frozen m tot_weight vset tot_stake best_stake - EQUAL // credits tot_stake frozen m tot_weight vset _253 + EQUAL // credits tot_stake frozen m tot_weight vset _251 49 THROWIFNOT - s3 s3 s4 XCHG3 - SWAP // credits vset tot_weight frozen tot_stake m + s4 s4 XCHG2 + s3 s1 s3 XCHG3 // credits vset tot_weight frozen tot_stake m }> conduct_elections PROC:<{ // ds elect credits @@ -1167,8 +1144,8 @@ PROGRAM{ 10 BLKDROP // FALSE // _38 }> // ds credits elect_at elect_close min_total_stake total_stake members max_stake_factor min_stake max_stake - s3 s8 XCHG - s8 PUSH + s3 PUSH + s4 s9 XCHG s3 s2 XCPU s7 s7 XCHG2 // ds members elect_at elect_close min_stake total_stake credits members min_stake max_stake min_total_stake max_stake_factor try_elect CALLDICT // ds members elect_at elect_close min_stake total_stake credits vdict total_weight frozen total_stakes cnt @@ -1186,13 +1163,8 @@ PROGRAM{ s3 PUSH // ds total_weight elect_at frozen total_stakes cnt credits vdict elect cnt IFNOTJMP:<{ // ds total_weight elect_at frozen total_stakes cnt credits vdict elect NIP - s2 POP - s2 POP - s2 POP - s2 POP - s2 POP // ds elect credits - NEWC // ds elect credits _49 - s1 s2 XCHG // ds credits elect _49 + 5 2 BLKDROP2 + NEWC // ds credits elect _49 STDICT // ds credits _50 STDICT // ds _51 SWAP // _51 ds @@ -1266,8 +1238,8 @@ PROGRAM{ s0 s3 s4 XCHG3 32 PUSHINT // ds elect credits _121 elect_at past_elect _122=32 DICTUSETB // ds elect credits past_elect - NEWC // ds elect credits past_elect _124 - s1 s3 XCHG // ds past_elect credits elect _124 + s0 s2 XCHG + NEWC // ds past_elect credits elect _124 STDICT // ds past_elect credits _125 STDICT // ds past_elect _126 STDICT // ds _127 @@ -1315,79 +1287,75 @@ PROGRAM{ s0 s0 s4 XCHG3 32 PUSHINT // elect credits cur_hash grams _39 active_id past_elect _40=32 DICTUSETB // elect credits cur_hash grams past_elect + s0 s2 XCHG // elect credits past_elect grams cur_hash }>ELSE<{ - s1 s5 XCHG s1 s3 XCHG - 3 BLKDROP // elect credits cur_hash grams past_elect + 3 BLKDROP // elect credits past_elect grams cur_hash }> }>ELSE<{ - s4 s1 s4 XCHG3 - 2DROP // elect credits cur_hash grams past_elect + 2 1 BLKDROP2 // elect credits past_elect grams cur_hash }> - -1 PUSHINT // elect credits cur_hash grams past_elect id=-1 + -1 PUSHINT // elect credits past_elect grams cur_hash id=-1 UNTIL:<{ - OVER - 32 PUSHINT // elect credits cur_hash grams past_elect id past_elect _46=32 + s3 PUSH + 32 PUSHINT // elect credits past_elect grams cur_hash id past_elect _46=32 DICTUGETNEXT - NULLSWAPIFNOT - NULLSWAPIFNOT // elect credits cur_hash grams past_elect fs id f - DUP // elect credits cur_hash grams past_elect fs id f f - IF:<{ // elect credits cur_hash grams past_elect fs id f - s0 s2 XCHG // elect credits cur_hash grams past_elect f id fs - 64 LDU // elect credits cur_hash grams past_elect f id _50 fs - 256 LDU // elect credits cur_hash grams past_elect f id tm hash fs - s1 s7 PUSH2 // elect credits cur_hash grams past_elect f id tm hash fs hash cur_hash - EQUAL // elect credits cur_hash grams past_elect f id tm hash fs _56 - IF:<{ // elect credits cur_hash grams past_elect f id tm hash fs - s4 POP // elect credits cur_hash grams past_elect fs id tm hash - s0 s3 XCHG // elect credits cur_hash grams past_elect hash id tm fs - LDDICT // elect credits cur_hash grams past_elect hash id tm _60 fs - LDGRAMS // elect credits cur_hash grams past_elect hash id tm _60 _62 fs - LDGRAMS // elect credits cur_hash grams past_elect hash id tm dict total_stake bonuses fs - s8 PUSH // elect credits cur_hash grams past_elect hash id tm dict total_stake bonuses fs grams - 3 RSHIFT# // elect credits cur_hash grams past_elect hash id tm dict total_stake bonuses fs amount - s9 s9 XCPU // elect credits cur_hash amount past_elect hash id tm dict total_stake bonuses fs grams amount - SUB // elect credits cur_hash amount past_elect hash id tm dict total_stake bonuses fs grams - s2 s9 XCHG2 // elect credits cur_hash grams past_elect hash id tm dict total_stake fs bonuses amount - ADD // elect credits cur_hash grams past_elect hash id tm dict total_stake fs bonuses - NEWC // elect credits cur_hash grams past_elect hash id tm dict total_stake fs bonuses _72 - s1 s5 XCHG // elect credits cur_hash grams past_elect hash id bonuses dict total_stake fs tm _72 - 64 STU // elect credits cur_hash grams past_elect hash id bonuses dict total_stake fs _74 - s1 s6 XCHG // elect credits cur_hash grams past_elect fs id bonuses dict total_stake hash _74 - 256 STU // elect credits cur_hash grams past_elect fs id bonuses dict total_stake _76 - s1 s2 XCHG // elect credits cur_hash grams past_elect fs id bonuses total_stake dict _76 - STDICT // elect credits cur_hash grams past_elect fs id bonuses total_stake _77 - SWAP // elect credits cur_hash grams past_elect fs id bonuses _77 total_stake - STGRAMS // elect credits cur_hash grams past_elect fs id bonuses _78 - SWAP // elect credits cur_hash grams past_elect fs id _78 bonuses - STGRAMS // elect credits cur_hash grams past_elect fs id _79 - ROT // elect credits cur_hash grams past_elect id _79 fs - STSLICER // elect credits cur_hash grams past_elect id _80 - SWAP - 32 PUSHINT - s1 s3 s3 PUXC2 // elect credits cur_hash grams id _80 id past_elect _81=32 - DICTUSETB // elect credits cur_hash grams id past_elect - FALSE // elect credits cur_hash grams id past_elect f + NULLSWAPIFNOT2 // elect credits past_elect grams cur_hash fs id f + DUP // elect credits past_elect grams cur_hash fs id f f + IF:<{ // elect credits past_elect grams cur_hash fs id f + s0 s2 XCHG // elect credits past_elect grams cur_hash f id fs + 64 LDU // elect credits past_elect grams cur_hash f id _50 fs + 256 LDU // elect credits past_elect grams cur_hash f id tm hash fs + s1 s5 PUSH2 // elect credits past_elect grams cur_hash f id tm hash fs hash cur_hash + EQUAL // elect credits past_elect grams cur_hash f id tm hash fs _56 + IF:<{ // elect credits past_elect grams cur_hash f id tm hash fs + s4 POP // elect credits past_elect grams cur_hash fs id tm hash + s0 s3 XCHG // elect credits past_elect grams cur_hash hash id tm fs + LDDICT // elect credits past_elect grams cur_hash hash id tm _60 fs + LDGRAMS // elect credits past_elect grams cur_hash hash id tm _60 _62 fs + LDGRAMS // elect credits past_elect grams cur_hash hash id tm dict total_stake bonuses fs + s8 PUSH // elect credits past_elect grams cur_hash hash id tm dict total_stake bonuses fs grams + 3 RSHIFT# // elect credits past_elect grams cur_hash hash id tm dict total_stake bonuses fs amount + s9 s9 XCPU // elect credits past_elect amount cur_hash hash id tm dict total_stake bonuses fs grams amount + SUB // elect credits past_elect amount cur_hash hash id tm dict total_stake bonuses fs grams + s2 s9 XCHG2 // elect credits past_elect grams cur_hash hash id tm dict total_stake fs bonuses amount + ADD // elect credits past_elect grams cur_hash hash id tm dict total_stake fs bonuses + s0 s4 XCHG + NEWC // elect credits past_elect grams cur_hash hash id bonuses dict total_stake fs tm _72 + 64 STU // elect credits past_elect grams cur_hash hash id bonuses dict total_stake fs _74 + s1 s6 XCHG // elect credits past_elect grams cur_hash fs id bonuses dict total_stake hash _74 + 256 STU // elect credits past_elect grams cur_hash fs id bonuses dict total_stake _76 + s1 s2 XCHG // elect credits past_elect grams cur_hash fs id bonuses total_stake dict _76 + STDICT // elect credits past_elect grams cur_hash fs id bonuses total_stake _77 + SWAP // elect credits past_elect grams cur_hash fs id bonuses _77 total_stake + STGRAMS // elect credits past_elect grams cur_hash fs id bonuses _78 + SWAP // elect credits past_elect grams cur_hash fs id _78 bonuses + STGRAMS // elect credits past_elect grams cur_hash fs id _79 + ROT // elect credits past_elect grams cur_hash id _79 fs + STSLICER // elect credits past_elect grams cur_hash id _80 + s0 s0 s4 XCPUXC + 32 PUSHINT // elect credits id grams cur_hash _80 id past_elect _81=32 + DICTUSETB // elect credits id grams cur_hash past_elect + s0 s3 XCHG + FALSE + SWAP // elect credits past_elect grams cur_hash f id }>ELSE<{ - s3 s5 XCHG - s3 s4 XCHG - 3 BLKDROP // elect credits cur_hash grams id past_elect f + 3 BLKDROP // elect credits past_elect grams cur_hash f id }> }>ELSE<{ - s3 s0 s3 XCHG3 - DROP // elect credits cur_hash grams id past_elect f + s2 POP // elect credits past_elect grams cur_hash f id }> - NOT // elect credits cur_hash grams id past_elect _84 - s1 s2 XCHG // elect credits cur_hash grams past_elect id _84 - }> // elect credits cur_hash grams past_elect id - DUP // elect credits cur_hash grams past_elect id id - ISNULL // elect credits cur_hash grams past_elect id _85 - IF:<{ // elect credits cur_hash grams past_elect id - DROP // elect credits cur_hash grams past_elect - 0 PUSHINT // elect credits cur_hash grams past_elect _86=0 - }>ELSE<{ // elect credits cur_hash grams past_elect _86 - }> // elect credits active_hash grams past_elect active_id - s0 s3 XCHG2 // elect credits past_elect grams active_id active_hash + SWAP // elect credits past_elect grams cur_hash id f + NOT // elect credits past_elect grams cur_hash id _84 + }> // elect credits past_elect grams cur_hash id + DUP // elect credits past_elect grams cur_hash id id + ISNULL // elect credits past_elect grams cur_hash id _85 + IF:<{ // elect credits past_elect grams cur_hash id + DROP // elect credits past_elect grams cur_hash + 0 PUSHINT // elect credits past_elect grams cur_hash _86=0 + }>ELSE<{ // elect credits past_elect grams cur_hash _86 + }> // elect credits past_elect grams active_hash active_id + SWAP // elect credits past_elect grams active_id active_hash store_data CALLDICT TRUE // _89 }> @@ -1463,8 +1431,7 @@ PROGRAM{ s4 PUSH 32 PUSHINT // elect credits past_elect grams active_id active_hash id past_elect _11=32 DICTUGETNEXT - NULLSWAPIFNOT - NULLSWAPIFNOT // elect credits past_elect grams active_id active_hash fs id f + NULLSWAPIFNOT2 // elect credits past_elect grams active_id active_hash fs id f DUP // elect credits past_elect grams active_id active_hash fs id f f IF:<{ // elect credits past_elect grams active_id active_hash fs id f s0 s2 XCHG // elect credits past_elect grams active_id active_hash f id fs @@ -1484,21 +1451,16 @@ PROGRAM{ s6 s1 s3 PUSH3 s3 s5 s8 PUSH3 // elect active_hash id past_elect active_id credits grams elect credits past_elect grams active_id active_hash store_data CALLDICT - FALSE // elect active_hash id past_elect active_id credits grams f - }>ELSE<{ - s6 s1 s5 XCHG3 - s4 s4 XCHG2 // elect active_hash id past_elect active_id credits grams f - }> + s0 s3 XCHG + s5 s4 XCHG2 + FALSE + SWAP // elect credits past_elect grams active_id active_hash f id + }> // elect credits past_elect grams active_id active_hash f id }>ELSE<{ - s3 s7 XCHG - s1 s6 XCHG - s5 s0 s5 XCHG3 - DROP // elect active_hash id past_elect active_id credits grams f + s2 POP // elect credits past_elect grams active_id active_hash f id }> - NOT // elect active_hash id past_elect active_id credits grams _26 - s2 s6 XCHG - s4 s5 XCHG - s1 s4 XCHG // elect credits past_elect grams active_id active_hash id _26 + SWAP // elect credits past_elect grams active_id active_hash id f + NOT // elect credits past_elect grams active_id active_hash id _26 }> // elect credits past_elect grams active_id active_hash id s0 s6 XCHG 6 BLKDROP // id @@ -1538,7 +1500,7 @@ PROGRAM{ 3 BLKDROP // FALSE // _27 }> // ds credits cur_vset - get_validator_conf CALLDICT // ds credits cur_vset _76 _77 _78 _79 + get_validator_conf CALLDICT // ds credits cur_vset _74 _75 _76 _77 DROP s2 POP // ds credits cur_vset elect_end_before elect_begin_before s0 s2 XCHG // ds credits elect_begin_before elect_end_before cur_vset @@ -1566,28 +1528,27 @@ PROGRAM{ 17 PUSHINT // ds credits elect_begin_before elect_end_before t _52=17 CONFIGOPTPARAM // ds credits elect_begin_before elect_end_before t _53 CTOS // ds credits elect_begin_before elect_end_before t _54 - LDGRAMS // ds credits elect_begin_before elect_end_before t _81 _80 + LDGRAMS // ds credits elect_begin_before elect_end_before t _79 _78 DROP // ds credits elect_begin_before elect_end_before t min_stake s0 s3 XCHG // ds credits min_stake elect_end_before t elect_begin_before ADD // ds credits min_stake elect_end_before elect_at - s0 DUMP // ds credits min_stake elect_end_before elect_at s0 s1 PUXC // ds credits min_stake elect_at elect_at elect_end_before SUB // ds credits min_stake elect_at elect_close - 0 PUSHINT // ds credits min_stake elect_at elect_close _62=0 - NEWDICT // ds credits min_stake elect_at elect_close _62=0 _63 - FALSE // ds credits min_stake elect_at elect_close _62=0 _63 _64 - s4 s5 XCHG + 0 PUSHINT // ds credits min_stake elect_at elect_close _60=0 + NEWDICT // ds credits min_stake elect_at elect_close _60=0 _61 s3 s4 XCHG - FALSE // ds credits elect_at elect_close min_stake _62=0 _63 _64 _65 + s2 s3 XCHG + FALSE + FALSE // ds credits elect_at elect_close min_stake _60=0 _61 _62 _63 pack_elect CALLDICT // ds credits elect - NEWC // ds credits elect _67 - STDICT // ds credits _68 - STDICT // ds _69 - SWAP // _69 ds - STSLICER // _70 - ENDC // _71 + NEWC // ds credits elect _65 + STDICT // ds credits _66 + STDICT // ds _67 + SWAP // _67 ds + STSLICER // _68 + ENDC // _69 c4 POP - TRUE // _73 + TRUE // _71 }> run_ticktock PROC:<{ // is_tock @@ -1675,28 +1636,73 @@ PROGRAM{ s2 PUSH 8 PUSHPOW2 // members l id members _28=256 DICTUGETPREV - NULLSWAPIFNOT - NULLSWAPIFNOT // members l fs id f + NULLSWAPIFNOT2 // members l fs id f DUP // members l fs id f f IF:<{ // members l fs id f s0 s2 XCHG // members l f id fs LDGRAMS // members l f id _46 _45 - DROP // members l f id _30 - s1 s(-1) PUXC // members l f id id _30 - PAIR // members l f id _32 - s0 s3 XCHG2 // members id f _32 l + DROP // members l f id _31 + s1 s(-1) PUXC // members l f id id _31 + PAIR // members l f id _30 + s0 s3 XCHG2 // members id f _30 l CONS // members id f l + s0 s2 XCHG // members l f id }>ELSE<{ - 2SWAP - DROP // members id f l + s2 POP // members l f id }> - SWAP // members id l f - NOT // members id l _34 - s1 s2 XCHG // members l id _34 + SWAP // members l id f + NOT // members l id _34 }> // members l id DROP NIP // l }> + participant_list_extended PROC:<{ + // + c4 PUSH // _1 + CTOS // _2 + PLDDICT // elect + DUP // elect elect + ISNULL // elect _4 + IFJMP:<{ // elect + DROP // + 0 PUSHINT // _5=0 + s0 s0 s0 PUSH3 // _5=0 _6=0 _7=0 _8=0 + PUSHNULL // _5=0 _6=0 _7=0 _8=0 _9 + s1 s1 PUSH2 // _5=0 _6=0 _7=0 _8=0 _9 _10=0 _11=0 + }> // elect + unpack_elect CALLDICT // elect_at elect_close min_stake total_stake members failed finished + PUSHNULL // elect_at elect_close min_stake total_stake members failed finished l + 256 PUSHPOW2DEC // elect_at elect_close min_stake total_stake members failed finished l id + UNTIL:<{ + s4 PUSH + 8 PUSHPOW2 // elect_at elect_close min_stake total_stake members failed finished l id members _34=256 + DICTUGETPREV + NULLSWAPIFNOT2 // elect_at elect_close min_stake total_stake members failed finished l cs id f + DUP // elect_at elect_close min_stake total_stake members failed finished l cs id f f + IF:<{ // elect_at elect_close min_stake total_stake members failed finished l cs id f + s0 s2 XCHG // elect_at elect_close min_stake total_stake members failed finished l f id cs + LDGRAMS // elect_at elect_close min_stake total_stake members failed finished l f id _41 cs + 32 LDU // elect_at elect_close min_stake total_stake members failed finished l f id _41 _73 _72 + NIP // elect_at elect_close min_stake total_stake members failed finished l f id _41 cs + 32 LDU // elect_at elect_close min_stake total_stake members failed finished l f id _41 _46 cs + 256 LDU // elect_at elect_close min_stake total_stake members failed finished l f id _41 _46 _49 cs + 256 LDU // elect_at elect_close min_stake total_stake members failed finished l f id stake max_factor addr adnl_addr cs + ENDS + 4 TUPLE // elect_at elect_close min_stake total_stake members failed finished l f id _57 + s1 s(-1) PUXC // elect_at elect_close min_stake total_stake members failed finished l f id id _57 + PAIR // elect_at elect_close min_stake total_stake members failed finished l f id _56 + s0 s3 XCHG2 // elect_at elect_close min_stake total_stake members failed finished id f _56 l + CONS // elect_at elect_close min_stake total_stake members failed finished id f l + s0 s2 XCHG // elect_at elect_close min_stake total_stake members failed finished l f id + }>ELSE<{ + s2 POP // elect_at elect_close min_stake total_stake members failed finished l f id + }> + SWAP // elect_at elect_close min_stake total_stake members failed finished l id f + NOT // elect_at elect_close min_stake total_stake members failed finished l id _59 + }> // elect_at elect_close min_stake total_stake members failed finished l id + DROP + s3 POP // elect_at elect_close min_stake total_stake l failed finished + }> compute_returned_stake PROC:<{ // wallet_addr c4 PUSH // wallet_addr _2 diff --git a/submodules/ton/tonlib-src/crypto/smartcont/auto/highload-wallet-code.cpp b/submodules/ton/tonlib-src/crypto/smartcont/auto/highload-wallet-code.cpp index ecc0b71d8e..e3408b9db9 100644 --- a/submodules/ton/tonlib-src/crypto/smartcont/auto/highload-wallet-code.cpp +++ b/submodules/ton/tonlib-src/crypto/smartcont/auto/highload-wallet-code.cpp @@ -1 +1 @@ -with_tvm_code("highload-wallet", "te6ccgEBBgEAhgABFP8A9KQT9KDyyAsBAgEgAgMCAUgEBQC88oMI1xgg0x/TH9Mf+CMTu/Jj7UTQ0x/TH9P/0VEyuvKhUUS68qIE+QFUEFX5EPKj9ATR+AB/jhghgBD0eG+hb6EgmALTB9QwAfsAkTLiAbPmWwGkyMsfyx/L/8ntVAAE0DAAEaCZL9qJoa4WPw=="); +with_tvm_code("highload-wallet", "te6ccgEBCAEAlwABFP8A9KQT9LzyyAsBAgEgAgMCAUgEBQC48oMI1xgg0x/TH9Mf+CMTu/Jj7UTQ0x/TH9P/0VEyuvKhUUS68qIE+QFUEFX5EPKj9ATR+AB/jhYhgBD0eG+lIJgC0wfUMAH7AJEy4gGz5lsBpMjLH8sfy//J7VQABNAwAgFIBgcAF7s5ztRNDTPzHXC/+AARuMl+1E0NcLH4"); diff --git a/submodules/ton/tonlib-src/crypto/smartcont/auto/highload-wallet-code.fif b/submodules/ton/tonlib-src/crypto/smartcont/auto/highload-wallet-code.fif index d2122a96fb..6dd5802739 100644 --- a/submodules/ton/tonlib-src/crypto/smartcont/auto/highload-wallet-code.fif +++ b/submodules/ton/tonlib-src/crypto/smartcont/auto/highload-wallet-code.fif @@ -3,6 +3,7 @@ PROGRAM{ DECLPROC recv_internal DECLPROC recv_external 85143 DECLMETHOD seqno + 78748 DECLMETHOD get_public_key recv_internal PROC:<{ // in_msg DROP // @@ -44,8 +45,7 @@ PROGRAM{ OVER 16 PUSHINT // public_key stored_seqno stored_subwallet dict i dict _57=16 DICTIGETNEXT - NULLSWAPIFNOT - NULLSWAPIFNOT // public_key stored_seqno stored_subwallet dict cs i f + NULLSWAPIFNOT2 // public_key stored_seqno stored_subwallet dict cs i f DUP // public_key stored_seqno stored_subwallet dict cs i f f IF:<{ // public_key stored_seqno stored_subwallet dict cs i f s0 s2 XCHG // public_key stored_seqno stored_subwallet dict f i cs @@ -76,4 +76,12 @@ PROGRAM{ CTOS // _1 32 PLDU // _3 }> + get_public_key PROC:<{ + // + c4 PUSH // _1 + CTOS // cs + 64 LDU // _9 _8 + NIP // cs + 256 PLDU // _7 + }> }END>c diff --git a/submodules/ton/tonlib-src/crypto/smartcont/auto/highload-wallet-v2-code.cpp b/submodules/ton/tonlib-src/crypto/smartcont/auto/highload-wallet-v2-code.cpp index ca5d2c70f7..ca5daab551 100644 --- a/submodules/ton/tonlib-src/crypto/smartcont/auto/highload-wallet-v2-code.cpp +++ b/submodules/ton/tonlib-src/crypto/smartcont/auto/highload-wallet-v2-code.cpp @@ -1 +1 @@ -with_tvm_code("highoad-wallet-v2", "te6ccgEBBwEA1wABFP8A9KQT9KDyyAsBAgEgAgMCAUgEBQHu8oMI1xgg0x/TP/gjqh9TILnyY+1E0NMf0z/T//QE0VNggED0Dm+hMfJgUXO68qIH+QFUEIf5EPKjAvQE0fgAf44YIYAQ9HhvoW+hIJgC0wfUMAH7AJEy4gGz5luDJaHIQDSAQPRDiuYxyBLLHxPLP8v/9ADJ7VQGAATQMABBoZfl2omhpj5jpn+n/mPoCaKkQQCB6BzfQmMktv8ld0fFADoggED0lm+hb6EyURCUMFMDud4gkjM2k0MTW+IBsw=="); +with_tvm_code("highload-wallet-v2", "te6ccgEBCQEA5QABFP8A9KQT9LzyyAsBAgEgAgMCAUgEBQHq8oMI1xgg0x/TP/gjqh9TILnyY+1E0NMf0z/T//QE0VNggED0Dm+hMfJgUXO68qIH+QFUEIf5EPKjAvQE0fgAf44WIYAQ9HhvpSCYAtMH1DAB+wCRMuIBs+ZbgyWhyEA0gED0Q4rmMQHIyx8Tyz/L//QAye1UCAAE0DACASAGBwAXvZznaiaGmvmOuF/8AEG+X5dqJoaY+Y6Z/p/5j6AmipEEAgegc30JjJLb/JXdHxQANCCAQPSWb6VsEiCUMFMDud4gkzM2AZJsIeKz"); diff --git a/submodules/ton/tonlib-src/crypto/smartcont/auto/highload-wallet-v2-code.fif b/submodules/ton/tonlib-src/crypto/smartcont/auto/highload-wallet-v2-code.fif index 9d5e467de5..5b2c64e0e2 100644 --- a/submodules/ton/tonlib-src/crypto/smartcont/auto/highload-wallet-v2-code.fif +++ b/submodules/ton/tonlib-src/crypto/smartcont/auto/highload-wallet-v2-code.fif @@ -3,6 +3,7 @@ PROGRAM{ DECLPROC recv_internal DECLPROC recv_external 117746 DECLMETHOD processed? + 78748 DECLMETHOD get_public_key recv_internal PROC:<{ // in_msg DROP // @@ -49,8 +50,7 @@ PROGRAM{ OVER 16 PUSHINT // last_cleaned public_key old_queries query_id stored_subwallet bound dict i dict _62=16 DICTIGETNEXT - NULLSWAPIFNOT - NULLSWAPIFNOT // last_cleaned public_key old_queries query_id stored_subwallet bound dict cs i f + NULLSWAPIFNOT2 // last_cleaned public_key old_queries query_id stored_subwallet bound dict cs i f DUP // last_cleaned public_key old_queries query_id stored_subwallet bound dict cs i f f IF:<{ // last_cleaned public_key old_queries query_id stored_subwallet bound dict cs i f s0 s2 XCHG // last_cleaned public_key old_queries query_id stored_subwallet bound dict f i cs @@ -76,10 +76,9 @@ PROGRAM{ DUP 64 PUSHINT // last_cleaned public_key stored_subwallet bound old_queries old_queries _85=64 DICTUREMMIN - NULLSWAPIFNOT - NULLSWAPIFNOT // last_cleaned public_key stored_subwallet bound old_queries _126 _128 _127 _129 - s2 POP // last_cleaned public_key stored_subwallet bound old_queries old_queries' f i - s1 s0 XCPU // last_cleaned public_key stored_subwallet bound old_queries old_queries' i f f + NULLSWAPIFNOT2 // last_cleaned public_key stored_subwallet bound old_queries _126 _128 _127 _129 + 1 2 BLKDROP2 // last_cleaned public_key stored_subwallet bound old_queries old_queries' i f + DUP // last_cleaned public_key stored_subwallet bound old_queries old_queries' i f f IF:<{ // last_cleaned public_key stored_subwallet bound old_queries old_queries' i f DROP // last_cleaned public_key stored_subwallet bound old_queries old_queries' i s0 s3 PUSH2 // last_cleaned public_key stored_subwallet bound old_queries old_queries' i i bound @@ -89,16 +88,15 @@ PROGRAM{ IF:<{ // last_cleaned public_key stored_subwallet bound old_queries old_queries' i f s3 POP s6 POP // last_cleaned public_key stored_subwallet bound f old_queries + SWAP // last_cleaned public_key stored_subwallet bound old_queries f }>ELSE<{ - s3 s1 s3 XCHG3 - 2DROP // last_cleaned public_key stored_subwallet bound f old_queries + 2 1 BLKDROP2 // last_cleaned public_key stored_subwallet bound old_queries f }> - SWAP // last_cleaned public_key stored_subwallet bound old_queries f NOT // last_cleaned public_key stored_subwallet bound old_queries _90 }> // last_cleaned public_key stored_subwallet bound old_queries NIP // last_cleaned public_key stored_subwallet old_queries - NEWC // last_cleaned public_key stored_subwallet old_queries _91 - s1 s2 XCHG // last_cleaned public_key old_queries stored_subwallet _91 + SWAP + NEWC // last_cleaned public_key old_queries stored_subwallet _91 32 STU // last_cleaned public_key old_queries _93 s1 s3 XCHG // old_queries public_key last_cleaned _93 64 STU // old_queries public_key _95 @@ -131,4 +129,12 @@ PROGRAM{ NEGATE // _24 }> }> + get_public_key PROC:<{ + // + c4 PUSH // _1 + CTOS // cs + 96 LDU // _11 _10 + NIP // cs + 256 PLDU // _9 + }> }END>c diff --git a/submodules/ton/tonlib-src/crypto/smartcont/auto/multisig-code.cpp b/submodules/ton/tonlib-src/crypto/smartcont/auto/multisig-code.cpp index 39ac8a7f6f..4c55e58f32 100644 --- a/submodules/ton/tonlib-src/crypto/smartcont/auto/multisig-code.cpp +++ b/submodules/ton/tonlib-src/crypto/smartcont/auto/multisig-code.cpp @@ -1 +1 @@ -with_tvm_code("multisig", "te6ccgECMAEAA2oAART/APSkE/Sg8sgLAQIBIAIDAgFICAkEwPIgxwCOgzDbPOCDCNcYIPkBAdMH2zwiwAAToVNhePQOb6Hyn9cL/0iQ+RDyoAP0BCD5AQHTP/gjqh9TILnyYVMngED0Dm+hECNUSADbPAquXLDyYrEBpPgAVDiTVHo5KxcvFgQEnts8VHCrU5rbPO1U+A9wJm5TqL6xmBA6EHlQdl8GiuIEgyWhjichgED0lm+hb6EyURCUMFMCud4glDQ2N3+XEEkQR0QUW+ICsxBXECXmMAMaHwUGAiowKkZTBts8UHegECQQN0EGU1bbPH8kGgEKipJfBeIHAQwQJNs87VQfAgLNCgsCASAbHAIBIAwNAgEgEhMCASAODwIBIBARAAMMIAEBIC8BASAfAQEgJAIBIBQVAgEgGBkBASAWAQEgFwA4jhXSAAHyo9MHWNcBIPkBBPkBFLrypFjgW3BSAgIc2zwC8mX4AFpxAts87VQvHwEBIBoATwhbpEx4CBukTDgAdAg10rDAJrUAvAHyFjPFszJ4HHXI8gBzxb0AMmAAaFIwvo4aXwOTIddKmAHTB9QC+wAB6DFwyMoAAoBA9EOOEnHIywATywdYzwFYzxYCgED0Q+ICASAdHgIBICUmARO77ZbVAjcFnbPIHwIBSCAhABjIywfLB8s/9AD0AMkCASAiIwF5sR10IMI1xgg+QEB0weCAdTE7UPYUyB49A5vofKf1wv/XjH5EPKgrgH0BCFulhAjXwNxAeD5AVjbPAGkAYCQAPa7agOgA6AD6AgF6AhH8gID8gN15T/gD5HoAAOeLZMAAFa4ZV0EA1WZ2oexAAGBwjikD0IMI1xjTB/QEMFMWePQOb6HypdcL/1RFRPkQ8qauUiCxUgO9FKEjbuYyMjICASAnKAIBSCkqAVW3JVtnhiZQCAqIhn6BzfQxwmYmQDpAADMaYOYuAFrgJhwLb+4cBgY3dG4QLwGNtVmbZ4Br4G/tscbqIlAIHo+N9C30JBHEgFpAADHDRA8a5CTa4GT2E5kAOeLAMAgKiCq+iHJCZhxSQmYcUktGHEA2fMCL4JAvAgEgKywCA5k4LS4BDawabZ4vgcAvABWt+UEAzJV2oewYQAENqTbPBRfBIC8AFa3cLOCAarM7UPYgABztRNDTB9MH0z/0BPQE0Q=="); +with_tvm_code("multisig", "te6ccgECKAEAA+YAART/APSkE/S88sgLAQIBIAIDAgFIBAUE3vIgxwCOgzDbPOCDCNcYIPkBAdMH2zwiwAAToVNxePQOb6EB2zwC8p9UGrv5EPKgBvQEIPkBAdMfURi68qrTP3BTAfAJAcIIAYMKvLHyaFMVgED0Dm+hIJgNpCDCCvJnDd/4I6ofU0C58mFUI6NTThweJB0CAswGBwIBIAoLAAPZhAIBSAgJAC1QKkItdJEqCTItdKlwLUAdAT8AnobBKABPQhbpEx4CBukTDgAdAg10rDAJrUAvAKyFjPFszJ4HHXI8gBzxb0AMmAIBIAwNAgEgEhMBFbvtltUDRwVSDbPIJwIBSA4PAgEgEBEBc7EddCDCNcYIPkBAdMHggHUxO1D2FMgePQOb6Hyn9cL/14x+RDyoK4B9AQhbpNbcTLg+QFY2zwBpAGAhAD2u2oDoAOgA+gIBegIR/ICA/IDdeU/4BWR6AADni2TAABWuGVdBANVmdqHsQAIBIBQVAgFIFhcBUbclW2eGJkZqRhAIHoHN9DHCTYRaQAAzGmHmLgBa4CYcC2/uHAt3dG4QHgGHtVmbZ4ar4G/tscaKInAIHo+N9KQRxGBaQAAxw0QQAhrkJLrgZPYTmQA54sqEAJAIHohgUiYcUiYcUiZcQDZiXMCL4JAeAgEgGBkCA5k4GhsBEawabZ4vgbYJQB4AFa35QQDMlXah7BhAAQ2pNs8FV8FgHgAVrdws4IBqsztQ9iACINs8AvJl+ABQQ3FDE9s87VQeJwSo2zwvrlMgsPJiErECpIIBhqD4AQWXAhEQAj4+MI6jAREQAQ/bPEDXePRDUxe5JoIgDhAAAAAAoCS8sPJpEL0QvAXiVBZbVHPnVhBT3Ns8VHEKVHq8HyUiIAAg7UTQ0x/TB9MH0z/0BPQE0QBIAY4aMNIAAfKj0wfTB1AD1wEg+QEF+QEVuvKkUAPgbCFwVCATBLjbPO1U+A9wJW5Tib6xmBBuEC1Qx18HjxswVCQDUE3bPFBVoEZQEEkQOksJU7nbPFBUFn/i+AAHgyWhjh0mgED0lm+lbBIglDBTArneIJY3OH85BwWSbCHis+YwBichIiMAYHCOKQPQgwjXGNMH9AQwUxZ49A5vofKl1wv/VEVE+RDypq5SILFSA70UoSNu5mwiMgKaUjC+jy5fA/gAkyLXSpgC0wfUAvsAAugycMjKAEAUgED0Q1MhePQOb6Ew2zyl2zxaePRDjhdxyMsAFMsHEssHWM8BWM8WQBOAQPRDAeIkJQEKipJfBuImAArT/9MHMAAMAcjL/8sHARQQRRA0QwDbPO1UJwAcyMsfywfLB8s/9AD0AMk="); diff --git a/submodules/ton/tonlib-src/crypto/smartcont/auto/multisig-code.fif b/submodules/ton/tonlib-src/crypto/smartcont/auto/multisig-code.fif index ce1c21bf08..14c6db1115 100644 --- a/submodules/ton/tonlib-src/crypto/smartcont/auto/multisig-code.fif +++ b/submodules/ton/tonlib-src/crypto/smartcont/auto/multisig-code.fif @@ -2,11 +2,14 @@ PROGRAM{ DECLPROC unpack_state DECLPROC pack_state + DECLPROC pack_owner_info + DECLPROC unpack_owner_info DECLPROC check_signatures DECLPROC recv_internal DECLPROC unpack_query_data DECLPROC try_init DECLPROC update_pending_queries + DECLPROC calc_boc_size DECLPROC recv_external 104746 DECLMETHOD get_query_state 117746 DECLMETHOD processed? @@ -23,22 +26,37 @@ PROGRAM{ // c4 PUSH // _1 CTOS // ds - 8 LDU // _4 ds + 32 LDU // _4 ds 8 LDU // _4 _7 ds - 64 LDU // _4 _7 _10 ds - LDDICT // _4 _7 _10 _13 ds - LDDICT // res res res res res ds + 8 LDU // _4 _7 _10 ds + 64 LDU // _4 _7 _10 _13 ds + LDDICT // _4 _7 _10 _13 _16 ds + LDDICT // res res res res res res ds ENDS }> pack_state PROCREF:<{ - // pending_queries public_keys last_cleaned k n - NEWC // pending_queries public_keys last_cleaned k n _5 - 8 STU // pending_queries public_keys last_cleaned k _7 - 8 STU // pending_queries public_keys last_cleaned _9 - 64 STU // pending_queries public_keys _11 - STDICT // pending_queries _12 - STDICT // _13 - ENDC // _14 + // pending_queries owner_infos last_cleaned k n wallet_id + NEWC // pending_queries owner_infos last_cleaned k n wallet_id _6 + 32 STU // pending_queries owner_infos last_cleaned k n _8 + 8 STU // pending_queries owner_infos last_cleaned k _10 + 8 STU // pending_queries owner_infos last_cleaned _12 + 64 STU // pending_queries owner_infos _14 + STDICT // pending_queries _15 + STDICT // _16 + ENDC // _17 + }> + pack_owner_info PROCREF:<{ + // public_key flood + SWAP + NEWC // flood public_key _2 + 256 STU // flood _4 + 8 STU // _6 + }> + unpack_owner_info PROCREF:<{ + // cs + 256 LDU // _1 cs + 8 LDU // _1 _10 _9 + DROP // _1 _4 }> check_signatures PROCREF:<{ // public_keys signatures hash cnt_bits @@ -70,8 +88,7 @@ PROGRAM{ s3 PUSH // public_keys signatures hash cnt_bits cnt signatures ISNULL // public_keys signatures hash cnt_bits cnt _37 }> // public_keys signatures hash cnt_bits cnt - s2 POP - s2 POP + 2 2 BLKDROP2 s2 POP // cnt cnt_bits }> recv_internal PROC:<{ @@ -79,78 +96,117 @@ PROGRAM{ DROP // }> unpack_query_data PROCREF:<{ - // in_msg n query found? - IFJMP:<{ // in_msg n query - 1 LDI // in_msg n _5 query - SWAP // in_msg n query _5 + // in_msg n query found? root_i + SWAP // in_msg n query root_i found? + IFJMP:<{ // in_msg n query root_i + DROP // in_msg n query + 1 LDI // in_msg n _6 query + SWAP // in_msg n query _6 35 THROWIFNOT - 8 LDU // in_msg n _12 query - ROT // in_msg _12 query n - LDUX // in_msg cnt cnt_bits msg - DUP // in_msg cnt cnt_bits msg msg - HASHSU // in_msg cnt cnt_bits msg _18 - s0 s4 XCHG // _18 cnt cnt_bits msg in_msg - HASHSU // _18 cnt cnt_bits msg _19 - s1 s4 XCHG // msg cnt cnt_bits _18 _19 - EQUAL // msg cnt cnt_bits _20 + 8 LDU // in_msg n _14 query + 8 LDU // in_msg n _14 _17 query + s0 s3 XCHG2 // in_msg _17 _14 query n + LDUX // in_msg cnt creator_i cnt_bits msg + DUP // in_msg cnt creator_i cnt_bits msg msg + HASHSU // in_msg cnt creator_i cnt_bits msg _23 + s0 s5 XCHG // _23 cnt creator_i cnt_bits msg in_msg + HASHSU // _23 cnt creator_i cnt_bits msg _24 + s1 s5 XCHG // msg cnt creator_i cnt_bits _23 _24 + EQUAL // msg cnt creator_i cnt_bits _25 36 THROWIFNOT - ROT // cnt cnt_bits msg - }> // in_msg n query - 2DROP // in_msg - 0 PUSHINT // in_msg _22=0 - s0 s1 PUXC // _22=0 _23=0 in_msg + s0 s3 XCHG2 // creator_i cnt cnt_bits msg + }> // in_msg n query root_i + 2 1 BLKDROP2 // in_msg root_i + 0 PUSHINT // in_msg root_i _27=0 + s0 s1 s2 XCPUXC // root_i _27=0 _28=0 in_msg }> try_init PROCREF:<{ // - unpack_state INLINECALLDICT // n k last_cleaned public_keys pending_queries - s0 s2 XCHG // n k pending_queries public_keys last_cleaned + unpack_state INLINECALLDICT // wallet_id n k last_cleaned owner_infos pending_queries + s0 s2 XCHG // wallet_id n k pending_queries owner_infos last_cleaned 37 THROWIF ACCEPT - 2SWAP + s4 s3 XCHG2 1 PUSHINT - s0 s2 XCHG // pending_queries public_keys _9=1 k n - pack_state INLINECALLDICT // _10 + s3 s1 s3 XCHG3 // pending_queries owner_infos _10=1 k n wallet_id + pack_state INLINECALLDICT // _11 c4 POP }> update_pending_queries PROCREF:<{ - // pending_queries msg query_id cnt cnt_bits n k - s3 s(-1) PUXC // pending_queries msg query_id cnt cnt_bits n cnt k - GEQ // pending_queries msg query_id cnt cnt_bits n _7 - IF:<{ // pending_queries msg query_id cnt cnt_bits n - 3 BLKDROP // pending_queries msg query_id + // pending_queries owner_infos msg query_id creator_i cnt cnt_bits n k + s3 s(-1) PUXC // pending_queries owner_infos msg query_id creator_i cnt cnt_bits n cnt k + GEQ // pending_queries owner_infos msg query_id creator_i cnt cnt_bits n _9 + IF:<{ // pending_queries owner_infos msg query_id creator_i cnt cnt_bits n + 3 BLKDROP // pending_queries owner_infos msg query_id creator_i + ACCEPT WHILE:<{ - OVER // pending_queries msg query_id msg - SREFS // pending_queries msg query_id _8 - }>DO<{ // pending_queries msg query_id - SWAP // pending_queries query_id msg - 8 LDU // pending_queries query_id mode msg - LDREF // pending_queries query_id mode _13 msg - s0 s2 XCHG // pending_queries query_id msg _13 mode + s2 PUSH // pending_queries owner_infos msg query_id creator_i msg + SREFS // pending_queries owner_infos msg query_id creator_i _11 + }>DO<{ // pending_queries owner_infos msg query_id creator_i + s0 s2 XCHG // pending_queries owner_infos creator_i query_id msg + 8 LDU // pending_queries owner_infos creator_i query_id mode msg + LDREF // pending_queries owner_infos creator_i query_id mode _16 msg + s0 s2 XCHG // pending_queries owner_infos creator_i query_id msg _16 mode SENDRAWMSG - SWAP // pending_queries msg query_id - }> // pending_queries msg query_id - NIP // pending_queries query_id - 0 PUSHINT // pending_queries query_id _17=0 - NEWC // pending_queries query_id _17=0 _18 - 1 STI // pending_queries query_id _20 - s0 s2 XCHG - 64 PUSHINT // _20 query_id pending_queries _21=64 - DICTUSETB // pending_queries - }>ELSE<{ // pending_queries msg query_id cnt cnt_bits n - 1 PUSHINT // pending_queries msg query_id cnt cnt_bits n _24=1 - NEWC // pending_queries msg query_id cnt cnt_bits n _24=1 _25 - 1 STU // pending_queries msg query_id cnt cnt_bits n _27 - s1 s3 XCHG // pending_queries msg query_id n cnt_bits cnt _27 - 8 STU // pending_queries msg query_id n cnt_bits _29 - ROT // pending_queries msg query_id cnt_bits _29 n - STUX // pending_queries msg query_id _30 - ROT // pending_queries query_id _30 msg - STSLICER // pending_queries query_id _31 - s0 s2 XCHG - 64 PUSHINT // _31 query_id pending_queries _32=64 - DICTUSETB // pending_queries + s0 s2 XCHG // pending_queries owner_infos msg query_id creator_i + }> // pending_queries owner_infos msg query_id creator_i + s2 POP // pending_queries owner_infos creator_i query_id + 0 PUSHINT // pending_queries owner_infos creator_i query_id _20=0 + NEWC // pending_queries owner_infos creator_i query_id _20=0 _21 + 1 STI // pending_queries owner_infos creator_i query_id _23 + s0 s1 s4 XCHG3 + 64 PUSHINT // creator_i owner_infos _23 query_id pending_queries _24=64 + DICTUSETB // creator_i owner_infos pending_queries + s2 s1 PUSH2 + 8 PUSHINT // creator_i owner_infos pending_queries creator_i owner_infos _28=8 + DICTUGET + NULLSWAPIFNOT // creator_i owner_infos pending_queries _56 _57 + DROP // creator_i owner_infos pending_queries owner_info + unpack_owner_info INLINECALLDICT // creator_i owner_infos pending_queries public_key flood + DEC // creator_i owner_infos pending_queries public_key _35 + pack_owner_info INLINECALLDICT // creator_i owner_infos pending_queries _36 + 2SWAP + 8 PUSHINT // pending_queries _36 creator_i owner_infos _37=8 + DICTUSETB // pending_queries owner_infos + }>ELSE<{ // pending_queries owner_infos msg query_id creator_i cnt cnt_bits n + 1 PUSHINT // pending_queries owner_infos msg query_id creator_i cnt cnt_bits n _40=1 + NEWC // pending_queries owner_infos msg query_id creator_i cnt cnt_bits n _40=1 _41 + 1 STU // pending_queries owner_infos msg query_id creator_i cnt cnt_bits n _43 + s1 s4 XCHG // pending_queries owner_infos msg query_id n cnt cnt_bits creator_i _43 + 8 STU // pending_queries owner_infos msg query_id n cnt cnt_bits _45 + s1 s2 XCHG // pending_queries owner_infos msg query_id n cnt_bits cnt _45 + 8 STU // pending_queries owner_infos msg query_id n cnt_bits _47 + ROT // pending_queries owner_infos msg query_id cnt_bits _47 n + STUX // pending_queries owner_infos msg query_id _48 + ROT // pending_queries owner_infos query_id _48 msg + STSLICER // pending_queries owner_infos query_id _49 + s0 s1 s3 XCHG3 + 64 PUSHINT // owner_infos _49 query_id pending_queries _50=64 + DICTUSETB // owner_infos pending_queries + SWAP // pending_queries owner_infos }> }> + calc_boc_size PROC:<{ + // cells bits root + s0 s2 XCHG // root bits cells + INC // root bits cells + s2 PUSH // root bits cells root + SBITS // root bits cells _5 + s1 s2 XCHG // root cells bits _5 + ADD // root cells bits + WHILE:<{ + s2 PUSH // root cells bits root + SREFS // root cells bits _7 + }>DO<{ // root cells bits + s0 s2 XCHG // bits cells root + LDREF // bits cells _8 root + SWAP // bits cells root _8 + CTOS // bits cells root _10 + s1 s3 XCHG // root cells bits _10 + calc_boc_size CALLDICT // root cells bits + }> // root cells bits + 1 2 BLKDROP2 // cells bits + }> recv_external PROC:<{ // in_msg DUP // in_msg in_msg @@ -165,157 +221,209 @@ PROGRAM{ HASHSU // root_signature in_msg root_hash SWAP // root_signature root_hash in_msg 8 LDU // root_signature root_hash root_i in_msg - unpack_state INLINECALLDICT // root_signature root_hash root_i in_msg n k last_cleaned public_keys pending_queries - s2 PUSH // root_signature root_hash root_i in_msg n k last_cleaned public_keys pending_queries last_cleaned - 0 EQINT // root_signature root_hash root_i in_msg n k last_cleaned public_keys pending_queries _20 - s1 s3 XCHG // root_signature root_hash root_i in_msg n k pending_queries public_keys last_cleaned _20 - SUB // root_signature root_hash root_i in_msg n k pending_queries public_keys last_cleaned - s6 s1 PUSH2 - 8 PUSHINT // root_signature root_hash root_i in_msg n k pending_queries public_keys last_cleaned root_i public_keys _24=8 + unpack_state INLINECALLDICT // root_signature root_hash root_i in_msg wallet_id n k last_cleaned owner_infos pending_queries + s2 PUSH // root_signature root_hash root_i in_msg wallet_id n k last_cleaned owner_infos pending_queries last_cleaned + 0 EQINT // root_signature root_hash root_i in_msg wallet_id n k last_cleaned owner_infos pending_queries _21 + s1 s3 XCHG // root_signature root_hash root_i in_msg wallet_id n k pending_queries owner_infos last_cleaned _21 + SUB // root_signature root_hash root_i in_msg wallet_id n k pending_queries owner_infos last_cleaned + s7 s1 PUSH2 + 8 PUSHINT // root_signature root_hash root_i in_msg wallet_id n k pending_queries owner_infos last_cleaned root_i owner_infos _25=8 DICTUGET - NULLSWAPIFNOT // root_signature root_hash root_i in_msg n k pending_queries public_keys last_cleaned public_key found? + NULLSWAPIFNOT // root_signature root_hash root_i in_msg wallet_id n k pending_queries owner_infos last_cleaned owner_info found? + SWAP // root_signature root_hash root_i in_msg wallet_id n k pending_queries owner_infos last_cleaned found? owner_info + unpack_owner_info INLINECALLDICT // root_signature root_hash root_i in_msg wallet_id n k pending_queries owner_infos last_cleaned found? public_key flood + s0 s2 XCHG // root_signature root_hash root_i in_msg wallet_id n k pending_queries owner_infos last_cleaned flood public_key found? 31 THROWIFNOT - 256 PLDU // root_signature root_hash root_i in_msg n k pending_queries public_keys last_cleaned _30 - s8 s9 s0 XCHG3 // last_cleaned public_keys root_i in_msg n k pending_queries root_hash root_signature _30 - CHKSIGNU // last_cleaned public_keys root_i in_msg n k pending_queries _31 + s10 s11 s11 XC2PU // public_key flood root_i in_msg wallet_id n k pending_queries owner_infos last_cleaned root_hash root_signature public_key + CHKSIGNU // public_key flood root_i in_msg wallet_id n k pending_queries owner_infos last_cleaned _33 32 THROWIFNOT - s0 s3 XCHG // last_cleaned public_keys root_i pending_queries n k in_msg - LDDICT // last_cleaned public_keys root_i pending_queries n k signatures in_msg - DUP // last_cleaned public_keys root_i pending_queries n k signatures in_msg in_msg - HASHSU // last_cleaned public_keys root_i pending_queries n k signatures in_msg hash - SWAP // last_cleaned public_keys root_i pending_queries n k signatures hash in_msg - 64 LDU // last_cleaned public_keys root_i pending_queries n k signatures hash query_id in_msg - NOW // last_cleaned public_keys root_i pending_queries n k signatures hash query_id in_msg _43 - 32 LSHIFT# // last_cleaned public_keys root_i pending_queries n k signatures hash query_id in_msg bound - s2 s0 PUSH2 // last_cleaned public_keys root_i pending_queries n k signatures hash query_id in_msg bound query_id bound - LESS // last_cleaned public_keys root_i pending_queries n k signatures hash query_id in_msg bound _47 - 33 THROWIF - s2 s7 PUSH2 - 64 PUSHINT // last_cleaned public_keys root_i pending_queries n k signatures hash query_id in_msg bound query_id pending_queries _51=64 + s0 s6 XCHG // public_key flood root_i last_cleaned wallet_id n k pending_queries owner_infos in_msg + LDDICT // public_key flood root_i last_cleaned wallet_id n k pending_queries owner_infos signatures in_msg + DUP // public_key flood root_i last_cleaned wallet_id n k pending_queries owner_infos signatures in_msg in_msg + HASHSU // public_key flood root_i last_cleaned wallet_id n k pending_queries owner_infos signatures in_msg hash + SWAP // public_key flood root_i last_cleaned wallet_id n k pending_queries owner_infos signatures hash in_msg + 32 LDU // public_key flood root_i last_cleaned wallet_id n k pending_queries owner_infos signatures hash query_wallet_id in_msg + s1 s8 XCPU // public_key flood root_i last_cleaned wallet_id n k pending_queries owner_infos signatures hash in_msg query_wallet_id wallet_id + EQUAL // public_key flood root_i last_cleaned wallet_id n k pending_queries owner_infos signatures hash in_msg _45 + 42 THROWIFNOT + 64 LDU // public_key flood root_i last_cleaned wallet_id n k pending_queries owner_infos signatures hash query_id in_msg + 0 PUSHINT // public_key flood root_i last_cleaned wallet_id n k pending_queries owner_infos signatures hash query_id in_msg _53=0 + s0 s1 PUSH2 // public_key flood root_i last_cleaned wallet_id n k pending_queries owner_infos signatures hash query_id in_msg _53=0 _54=0 in_msg + calc_boc_size CALLDICT // public_key flood root_i last_cleaned wallet_id n k pending_queries owner_infos signatures hash query_id in_msg cnt bits + SWAP // public_key flood root_i last_cleaned wallet_id n k pending_queries owner_infos signatures hash query_id in_msg bits cnt + 8 GTINT // public_key flood root_i last_cleaned wallet_id n k pending_queries owner_infos signatures hash query_id in_msg bits _58 + SWAP + 11 PUSHPOW2 // public_key flood root_i last_cleaned wallet_id n k pending_queries owner_infos signatures hash query_id in_msg _58 bits _59=2048 + GREATER // public_key flood root_i last_cleaned wallet_id n k pending_queries owner_infos signatures hash query_id in_msg _58 _60 + OR // public_key flood root_i last_cleaned wallet_id n k pending_queries owner_infos signatures hash query_id in_msg _61 + 40 THROWIF + s1 s5 PUSH2 + 64 PUSHINT // public_key flood root_i last_cleaned wallet_id n k pending_queries owner_infos signatures hash query_id in_msg query_id pending_queries _65=64 DICTUGET - NULLSWAPIFNOT // last_cleaned public_keys root_i pending_queries n k signatures hash query_id in_msg bound query found? - s2 s3 XCHG - s8 s(-1) s(-1) PUXC2 // last_cleaned public_keys root_i pending_queries n k signatures hash query_id bound in_msg n query found? - unpack_query_data INLINECALLDICT // last_cleaned public_keys root_i pending_queries n k signatures hash query_id bound cnt cnt_bits msg - s0 s10 XCHG // last_cleaned public_keys msg pending_queries n k signatures hash query_id bound cnt cnt_bits root_i - POW2 // last_cleaned public_keys msg pending_queries n k signatures hash query_id bound cnt cnt_bits mask - 2DUP // last_cleaned public_keys msg pending_queries n k signatures hash query_id bound cnt cnt_bits mask cnt_bits mask - AND // last_cleaned public_keys msg pending_queries n k signatures hash query_id bound cnt cnt_bits mask _61 + NULLSWAPIFNOT // public_key flood root_i last_cleaned wallet_id n k pending_queries owner_infos signatures hash query_id in_msg query found? + DUP // public_key flood root_i last_cleaned wallet_id n k pending_queries owner_infos signatures hash query_id in_msg query found? found? + IFNOT:<{ // public_key flood root_i last_cleaned wallet_id n k pending_queries owner_infos signatures hash query_id in_msg query found? + s0 s13 XCHG // public_key found? root_i last_cleaned wallet_id n k pending_queries owner_infos signatures hash query_id in_msg query flood + INC // public_key found? root_i last_cleaned wallet_id n k pending_queries owner_infos signatures hash query_id in_msg query flood + DUP // public_key found? root_i last_cleaned wallet_id n k pending_queries owner_infos signatures hash query_id in_msg query flood flood + 10 GTINT // public_key found? root_i last_cleaned wallet_id n k pending_queries owner_infos signatures hash query_id in_msg query flood _71 + 39 THROWIF + s0 s13 XCHG // public_key flood root_i last_cleaned wallet_id n k pending_queries owner_infos signatures hash query_id in_msg query found? + }> // public_key flood root_i last_cleaned wallet_id n k pending_queries owner_infos signatures hash query_id in_msg query found? + NOW // public_key flood root_i last_cleaned wallet_id n k pending_queries owner_infos signatures hash query_id in_msg query found? _74 + 32 LSHIFT# // public_key flood root_i last_cleaned wallet_id n k pending_queries owner_infos signatures hash query_id in_msg query found? bound + s4 s0 PUSH2 // public_key flood root_i last_cleaned wallet_id n k pending_queries owner_infos signatures hash query_id in_msg query found? bound query_id bound + LESS // public_key flood root_i last_cleaned wallet_id n k pending_queries owner_infos signatures hash query_id in_msg query found? bound _78 + 33 THROWIF + s3 s10 s2 XCPUXC + s4 s14 PUSH2 // public_key flood root_i last_cleaned wallet_id n k pending_queries owner_infos signatures hash query_id found? bound in_msg n query found? root_i + unpack_query_data INLINECALLDICT // public_key flood root_i last_cleaned wallet_id n k pending_queries owner_infos signatures hash query_id found? bound creator_i cnt cnt_bits msg + s15 PUSH // public_key flood root_i last_cleaned wallet_id n k pending_queries owner_infos signatures hash query_id found? bound creator_i cnt cnt_bits msg root_i + POW2 // public_key flood root_i last_cleaned wallet_id n k pending_queries owner_infos signatures hash query_id found? bound creator_i cnt cnt_bits msg mask + s2 s0 PUSH2 // public_key flood root_i last_cleaned wallet_id n k pending_queries owner_infos signatures hash query_id found? bound creator_i cnt cnt_bits msg mask cnt_bits mask + AND // public_key flood root_i last_cleaned wallet_id n k pending_queries owner_infos signatures hash query_id found? bound creator_i cnt cnt_bits msg mask _89 34 THROWIF - OR // last_cleaned public_keys msg pending_queries n k signatures hash query_id bound cnt cnt_bits - SWAP // last_cleaned public_keys msg pending_queries n k signatures hash query_id bound cnt_bits cnt - INC // last_cleaned public_keys msg pending_queries n k signatures hash query_id bound cnt_bits cnt - ACCEPT - s8 s9 s3 XCPU2 - s10 s3 s9 PUSH3 - s11 PUSH // last_cleaned public_keys msg cnt n k signatures hash query_id bound cnt_bits pending_queries msg query_id cnt cnt_bits n k - update_pending_queries INLINECALLDICT // last_cleaned public_keys msg cnt n k signatures hash query_id bound cnt_bits pending_queries - s0 s10 s11 PUSH3 - s9 s10 PUSH2 // last_cleaned public_keys msg cnt n k signatures hash query_id bound cnt_bits pending_queries pending_queries public_keys last_cleaned k n - pack_state INLINECALLDICT // last_cleaned public_keys msg cnt n k signatures hash query_id bound cnt_bits pending_queries _68 + s1 s2 XCHG // public_key flood root_i last_cleaned wallet_id n k pending_queries owner_infos signatures hash query_id found? bound creator_i cnt msg cnt_bits mask + OR // public_key flood root_i last_cleaned wallet_id n k pending_queries owner_infos signatures hash query_id found? bound creator_i cnt msg cnt_bits + s0 s2 XCHG // public_key flood root_i last_cleaned wallet_id n k pending_queries owner_infos signatures hash query_id found? bound creator_i cnt_bits msg cnt + INC // public_key flood root_i last_cleaned wallet_id n k pending_queries owner_infos signatures hash query_id found? bound creator_i cnt_bits msg cnt + 100000 PUSHINT // public_key flood root_i last_cleaned wallet_id n k pending_queries owner_infos signatures hash query_id found? bound creator_i cnt_bits msg cnt _94=100000 + SETGASLIMIT + s0 s5 XCHG // public_key flood root_i last_cleaned wallet_id n k pending_queries owner_infos signatures hash query_id cnt bound creator_i cnt_bits msg found? + IFNOT:<{ // public_key flood root_i last_cleaned wallet_id n k pending_queries owner_infos signatures hash query_id cnt bound creator_i cnt_bits msg + s1 16 s() XCHG + s0 s15 XCHG // cnt_bits msg root_i last_cleaned wallet_id n k pending_queries owner_infos signatures hash query_id cnt bound creator_i public_key flood + pack_owner_info INLINECALLDICT // cnt_bits msg root_i last_cleaned wallet_id n k pending_queries owner_infos signatures hash query_id cnt bound creator_i _97 + s0 s13 s7 XCHG3 + 8 PUSHINT // cnt_bits msg creator_i last_cleaned wallet_id n k pending_queries bound signatures hash query_id cnt _97 root_i owner_infos _98=8 + DICTUSETB // cnt_bits msg creator_i last_cleaned wallet_id n k pending_queries bound signatures hash query_id cnt owner_infos + s1 s7 PUSH2 // cnt_bits msg creator_i last_cleaned wallet_id n k pending_queries bound signatures hash query_id cnt owner_infos cnt k + LESS // cnt_bits msg creator_i last_cleaned wallet_id n k pending_queries bound signatures hash query_id cnt owner_infos _101 + s6 PUSH + 15461882265600 PUSHINT // cnt_bits msg creator_i last_cleaned wallet_id n k pending_queries bound signatures hash query_id cnt owner_infos _101 bound _106 + ADD // cnt_bits msg creator_i last_cleaned wallet_id n k pending_queries bound signatures hash query_id cnt owner_infos _101 _107 + s4 PUSH // cnt_bits msg creator_i last_cleaned wallet_id n k pending_queries bound signatures hash query_id cnt owner_infos _101 _107 query_id + GREATER // cnt_bits msg creator_i last_cleaned wallet_id n k pending_queries bound signatures hash query_id cnt owner_infos _101 _108 + AND // cnt_bits msg creator_i last_cleaned wallet_id n k pending_queries bound signatures hash query_id cnt owner_infos _109 + 41 THROWIF + s11 s13 XCHG + s11 s12 XCHG + s0 s5 XCHG // creator_i cnt_bits msg last_cleaned wallet_id n k pending_queries owner_infos signatures hash query_id cnt bound + }>ELSE<{ + s2 16 s() XCHG + s14 POP + s14 POP + DROP // creator_i cnt_bits msg last_cleaned wallet_id n k pending_queries owner_infos signatures hash query_id cnt bound + }> + s6 s5 s11 XC2PU + s3 s14 s7 PUSH3 + 16 s() PUSH + s13 s12 PUSH2 // creator_i cnt_bits msg last_cleaned wallet_id n k cnt bound signatures hash query_id pending_queries owner_infos msg query_id creator_i cnt cnt_bits n k + update_pending_queries INLINECALLDICT // creator_i cnt_bits msg last_cleaned wallet_id n k cnt bound signatures hash query_id pending_queries owner_infos + s1 s0 s10 PUSH3 + s10 s11 s12 PUSH3 // creator_i cnt_bits msg last_cleaned wallet_id n k cnt bound signatures hash query_id pending_queries owner_infos pending_queries owner_infos last_cleaned k n wallet_id + pack_state INLINECALLDICT // creator_i cnt_bits msg last_cleaned wallet_id n k cnt bound signatures hash query_id pending_queries owner_infos _112 c4 POP COMMIT - 0 PUSHINT // last_cleaned public_keys msg cnt n k signatures hash query_id bound cnt_bits pending_queries need_save=0 - s6 PUSH // last_cleaned public_keys msg cnt n k signatures hash query_id bound cnt_bits pending_queries need_save=0 signatures - ISNULL // last_cleaned public_keys msg cnt n k signatures hash query_id bound cnt_bits pending_queries need_save=0 _73 - s10 s8 PUSH2 // last_cleaned public_keys msg cnt n k signatures hash query_id bound cnt_bits pending_queries need_save=0 _73 cnt k - GEQ // last_cleaned public_keys msg cnt n k signatures hash query_id bound cnt_bits pending_queries need_save=0 _73 _74 - OR // last_cleaned public_keys msg cnt n k signatures hash query_id bound cnt_bits pending_queries need_save=0 _75 - IFNOT:<{ // last_cleaned public_keys msg cnt n k signatures hash query_id bound cnt_bits pending_queries need_save=0 - DROP // last_cleaned public_keys msg cnt n k signatures hash query_id bound cnt_bits pending_queries - s10 PUSH - s6 s5 s3 XCHG3 - s0 s6 XCHG // last_cleaned public_keys msg cnt n k bound pending_queries query_id public_keys signatures hash cnt_bits - check_signatures INLINECALLDICT // last_cleaned public_keys msg cnt n k bound pending_queries query_id new_cnt cnt_bits - s7 s7 XCHG2 // last_cleaned public_keys msg cnt_bits n k bound pending_queries query_id cnt new_cnt - ADD // last_cleaned public_keys msg cnt_bits n k bound pending_queries query_id cnt - s2 s4 XCHG - s3 s7 XCHG - s1 s0 s6 XCHG3 - s5 s6 PUSH2 // last_cleaned public_keys bound k n pending_queries msg query_id cnt cnt_bits n k - update_pending_queries INLINECALLDICT // last_cleaned public_keys bound k n pending_queries - -1 PUSHINT // last_cleaned public_keys bound k n pending_queries need_save=-1 - }>ELSE<{ + 0 PUSHINT // creator_i cnt_bits msg last_cleaned wallet_id n k cnt bound signatures hash query_id pending_queries owner_infos need_save=0 + s5 PUSH // creator_i cnt_bits msg last_cleaned wallet_id n k cnt bound signatures hash query_id pending_queries owner_infos need_save=0 signatures + ISNULL // creator_i cnt_bits msg last_cleaned wallet_id n k cnt bound signatures hash query_id pending_queries owner_infos need_save=0 _117 + s8 s9 PUSH2 // creator_i cnt_bits msg last_cleaned wallet_id n k cnt bound signatures hash query_id pending_queries owner_infos need_save=0 _117 cnt k + GEQ // creator_i cnt_bits msg last_cleaned wallet_id n k cnt bound signatures hash query_id pending_queries owner_infos need_save=0 _117 _118 + OR // creator_i cnt_bits msg last_cleaned wallet_id n k cnt bound signatures hash query_id pending_queries owner_infos need_save=0 _119 + IFNOT:<{ // creator_i cnt_bits msg last_cleaned wallet_id n k cnt bound signatures hash query_id pending_queries owner_infos need_save=0 + DROP // creator_i cnt_bits msg last_cleaned wallet_id n k cnt bound signatures hash query_id pending_queries owner_infos + s4 s0 s2 XCPUXC + s4 s13 XCHG2 // creator_i query_id msg last_cleaned wallet_id n k cnt bound pending_queries owner_infos owner_infos signatures hash cnt_bits + check_signatures INLINECALLDICT // creator_i query_id msg last_cleaned wallet_id n k cnt bound pending_queries owner_infos new_cnt cnt_bits + s5 s5 XCHG2 // creator_i query_id msg last_cleaned wallet_id n k cnt_bits bound pending_queries owner_infos cnt new_cnt + ADD // creator_i query_id msg last_cleaned wallet_id n k cnt_bits bound pending_queries owner_infos cnt + s6 s5 s0 XCHG3 + s4 s9 XCHG s3 s10 XCHG - s7 s9 XCHG - s7 s6 XCHG2 - 6 BLKDROP // last_cleaned public_keys bound k n pending_queries need_save + s11 s0 s9 XCHG3 + s11 s9 PUSH2 // n bound k last_cleaned wallet_id pending_queries owner_infos msg query_id creator_i cnt cnt_bits n k + update_pending_queries INLINECALLDICT // n bound k last_cleaned wallet_id pending_queries owner_infos + s5 s4 XCHG2 + s1 s6 XCHG + -1 PUSHINT // bound pending_queries owner_infos last_cleaned wallet_id n k need_save=-1 + }>ELSE<{ + s6 s14 XCHG + s2 s13 XCHG + s12 s7 XCHG2 + 7 BLKDROP // bound pending_queries owner_infos last_cleaned wallet_id n k need_save }> - s0 s4 XCHG - 38 PUSHPOW2 // last_cleaned public_keys need_save k n pending_queries bound _83 - SUB // last_cleaned public_keys need_save k n pending_queries bound + ACCEPT + s0 s7 XCHG + 38 PUSHPOW2 // need_save pending_queries owner_infos last_cleaned wallet_id n k bound _128 + SUB // need_save pending_queries owner_infos last_cleaned wallet_id n k bound UNTIL:<{ - OVER - 64 PUSHINT // last_cleaned public_keys need_save k n pending_queries bound pending_queries _90=64 + s6 PUSH + 64 PUSHINT // need_save pending_queries owner_infos last_cleaned wallet_id n k bound pending_queries _135=64 DICTUREMMIN - NULLSWAPIFNOT - NULLSWAPIFNOT // last_cleaned public_keys need_save k n pending_queries bound _121 _123 _122 _124 - s2 POP // last_cleaned public_keys need_save k n pending_queries bound pending_queries' f i - s1 s0 XCPU // last_cleaned public_keys need_save k n pending_queries bound pending_queries' i f f - IF:<{ // last_cleaned public_keys need_save k n pending_queries bound pending_queries' i f - DROP // last_cleaned public_keys need_save k n pending_queries bound pending_queries' i - s0 s2 PUSH2 // last_cleaned public_keys need_save k n pending_queries bound pending_queries' i i bound - LESS // last_cleaned public_keys need_save k n pending_queries bound pending_queries' i f - }> // last_cleaned public_keys need_save k n pending_queries bound pending_queries' i f - DUP // last_cleaned public_keys need_save k n pending_queries bound pending_queries' i f f - IF:<{ // last_cleaned public_keys need_save k n pending_queries bound pending_queries' i f - s4 POP - s6 POP - s7 POP // pending_queries public_keys last_cleaned k n f bound - -1 PUSHINT // pending_queries public_keys last_cleaned k n f bound need_save=-1 + NULLSWAPIFNOT2 // need_save pending_queries owner_infos last_cleaned wallet_id n k bound _178 _180 _179 _181 + 1 2 BLKDROP2 // need_save pending_queries owner_infos last_cleaned wallet_id n k bound pending_queries' i f + DUP // need_save pending_queries owner_infos last_cleaned wallet_id n k bound pending_queries' i f f + IF:<{ // need_save pending_queries owner_infos last_cleaned wallet_id n k bound pending_queries' i f + DROP // need_save pending_queries owner_infos last_cleaned wallet_id n k bound pending_queries' i + s0 s2 PUSH2 // need_save pending_queries owner_infos last_cleaned wallet_id n k bound pending_queries' i i bound + LESS // need_save pending_queries owner_infos last_cleaned wallet_id n k bound pending_queries' i f + }> // need_save pending_queries owner_infos last_cleaned wallet_id n k bound pending_queries' i f + DUP // need_save pending_queries owner_infos last_cleaned wallet_id n k bound pending_queries' i f f + IF:<{ // need_save pending_queries owner_infos last_cleaned wallet_id n k bound pending_queries' i f + s7 POP + s8 POP + -1 PUSHINT + s9 POP + s0 s7 XCHG + s0 s5 XCHG // need_save=-1 pending_queries owner_infos last_cleaned wallet_id n k bound f }>ELSE<{ - s4 s9 XCHG - s4 s7 XCHG - s4 s1 s4 XCHG3 - 2DROP // pending_queries public_keys last_cleaned k n f bound need_save + 2 1 BLKDROP2 // need_save pending_queries owner_infos last_cleaned wallet_id n k bound f }> - s0 s2 XCHG // pending_queries public_keys last_cleaned k n need_save bound f - NOT // pending_queries public_keys last_cleaned k n need_save bound _96 - s5 s7 XCHG - s2 s5 XCHG // last_cleaned public_keys need_save k n pending_queries bound _96 - }> // last_cleaned public_keys need_save k n pending_queries bound - DROP // last_cleaned public_keys need_save k n pending_queries - s0 s3 XCHG // last_cleaned public_keys pending_queries k n need_save - IF:<{ // last_cleaned public_keys pending_queries k n - s2 s4 XCHG // pending_queries public_keys last_cleaned k n - pack_state INLINECALLDICT // _97 + NOT // need_save pending_queries owner_infos last_cleaned wallet_id n k bound _141 + }> // need_save pending_queries owner_infos last_cleaned wallet_id n k bound + DROP // need_save pending_queries owner_infos last_cleaned wallet_id n k + s0 s6 XCHG // k pending_queries owner_infos last_cleaned wallet_id n need_save + IF:<{ // k pending_queries owner_infos last_cleaned wallet_id n + s4 s5 XCHG + s3 s4 XCHG + s3 s0 s0 XCHG3 // pending_queries owner_infos last_cleaned k n wallet_id + pack_state INLINECALLDICT // _142 c4 POP }>ELSE<{ - 5 BLKDROP // + 6 BLKDROP // }> }> get_query_state PROC:<{ // query_id - unpack_state INLINECALLDICT // query_id _25 _26 _27 _28 _29 + unpack_state INLINECALLDICT // query_id _28 _29 _30 _31 _32 _33 NIP - s2 POP // query_id n pending_queries last_cleaned - 64 PUSHINT // query_id n pending_queries last_cleaned _9=64 - s4 s2 s2 PUXC2 // query_id n last_cleaned query_id pending_queries _9=64 + s2 POP + s3 POP // query_id last_cleaned n pending_queries + s3 s(-1) PUXC + 64 PUSHINT // query_id last_cleaned n query_id pending_queries _10=64 DICTUGET - NULLSWAPIFNOT // query_id n last_cleaned cs found - IFJMP:<{ // query_id n last_cleaned cs - NIP - s2 POP // cs n - SWAP // n cs - 1 LDI // n _11 cs - SWAP // n cs _11 + NULLSWAPIFNOT // query_id last_cleaned n cs found + IFJMP:<{ // query_id last_cleaned n cs + 2 2 BLKDROP2 // n cs + 1 LDI // n _12 cs + SWAP // n cs _12 IFJMP:<{ // n cs - 8 LDU // n _35 _34 + 16 LDU // n _39 _38 NIP // n cs - 0 PUSHINT // n cs _17=0 - s0 s2 XCHG // _17=0 cs n - LDUX // _17=0 _37 _36 - DROP // _17=0 _18 + 0 PUSHINT // n cs _20=0 + s0 s2 XCHG // _20=0 cs n + LDUX // _20=0 _41 _40 + DROP // _20=0 _21 }> // n cs 2DROP // - -1 PUSHINT // _20=-1 - 0 PUSHINT // _20=-1 _21=0 - }> // query_id n last_cleaned cs - DROP - NIP // query_id last_cleaned - LEQ // _22 - NEGATE // _23 - 0 PUSHINT // _23 _24=0 + -1 PUSHINT // _23=-1 + 0 PUSHINT // _23=-1 _24=0 + }> // query_id last_cleaned n cs + 2DROP // query_id last_cleaned + LEQ // _25 + NEGATE // _26 + 0 PUSHINT // _26 _27=0 }> processed? PROC:<{ // query_id @@ -323,12 +431,12 @@ PROGRAM{ DROP // x }> create_init_state PROC:<{ - // n k public_keys - NEWDICT // n k public_keys _3 - s2 s3 XCHG2 + // wallet_id n k owners_info + NEWDICT // wallet_id n k owners_info _4 + s3 s4 XCHG2 0 PUSHINT - -ROT // _3 public_keys _4=0 k n - pack_state INLINECALLDICT // _5 + 3 -ROLL // _4 owners_info _5=0 k n wallet_id + pack_state INLINECALLDICT // _6 }> merge_list PROC:<{ // a b @@ -351,7 +459,7 @@ PROGRAM{ LDREF // b _10 as s0 s2 XCHG // as _10 b merge_list CALLDICT // as tail - NEWC // as tail _13 + NEWC ROT // tail _13 as STSLICER // tail _14 STREF // _15 @@ -367,9 +475,9 @@ PROGRAM{ }> get_public_keys PROC:<{ // - unpack_state INLINECALLDICT // _6 _7 _8 _9 _10 - s1 s4 XCHG - 4 BLKDROP // public_keys + unpack_state INLINECALLDICT // _7 _8 _9 _10 _11 _12 + s1 s5 XCHG + 5 BLKDROP // public_keys }> check_query_signatures PROC:<{ // query @@ -396,10 +504,9 @@ PROGRAM{ OVER // public_keys mask signatures cs signatures ISNULL // public_keys mask signatures cs _32 IFJMP:<{ // public_keys mask signatures cs - s2 s3 XCHG - 3 BLKDROP // mask - 1 PUSHINT // mask _33=1 - SWAP // _33=1 mask + 2DROP + 1 PUSHINT + s2 POP // _33=1 mask }> // public_keys mask signatures cs HASHSU // public_keys mask signatures _35 ROT // public_keys signatures _35 mask @@ -410,53 +517,50 @@ PROGRAM{ }> messages_by_mask PROC:<{ // mask - unpack_state INLINECALLDICT // mask _29 _30 _31 _32 _33 - s0 s3 XCHG - 3 BLKDROP // mask n pending_queries - -1 PUSHINT // mask n pending_queries i=-1 - NEWDICT // mask n pending_queries i=-1 a + unpack_state INLINECALLDICT // mask _32 _33 _34 _35 _36 _37 + s5 POP + 3 BLKDROP // mask pending_queries n + -1 PUSHINT // mask pending_queries n i=-1 + NEWDICT // mask pending_queries n i=-1 a UNTIL:<{ - s1 s2 XCPU - 64 PUSHINT // mask n pending_queries a i pending_queries _13=64 + s1 s3 XCPU + 64 PUSHINT // mask pending_queries n a i pending_queries _14=64 DICTUGETNEXT - NULLSWAPIFNOT - NULLSWAPIFNOT // mask n pending_queries a cs i f - DUP // mask n pending_queries a cs i f f - IF:<{ // mask n pending_queries a cs i f - s0 s2 XCHG // mask n pending_queries a f i cs - 1 LDI // mask n pending_queries a f i _15 cs - SWAP // mask n pending_queries a f i cs _15 - IF:<{ // mask n pending_queries a f i cs + NULLSWAPIFNOT2 // mask pending_queries n a cs i f + DUP // mask pending_queries n a cs i f f + IF:<{ // mask pending_queries n a cs i f + s0 s2 XCHG // mask pending_queries n a f i cs + 1 LDI // mask pending_queries n a f i _16 cs + SWAP // mask pending_queries n a f i cs _16 + IF:<{ // mask pending_queries n a f i cs DUP - 8 PUSHINT // mask n pending_queries a f i cs cs _19=8 - SDSKIPFIRST // mask n pending_queries a f i cs _20 - s6 PUSH // mask n pending_queries a f i cs _20 n - PLDUX // mask n pending_queries a f i cs cnt_bits - s7 PUSH // mask n pending_queries a f i cs cnt_bits mask - AND // mask n pending_queries a f i cs _22 - IF:<{ // mask n pending_queries a f i cs - NEWC // mask n pending_queries a f i cs _24 - SWAP // mask n pending_queries a f i _24 cs - STSLICER // mask n pending_queries a f i _25 - SWAP - 64 PUSHINT - s1 s4 s4 PUXC2 // mask n pending_queries i f _25 i a _26=64 - DICTUSETB // mask n pending_queries i f a + 16 PUSHINT // mask pending_queries n a f i cs cs _22 + SDSKIPFIRST // mask pending_queries n a f i cs _23 + s5 PUSH // mask pending_queries n a f i cs _23 n + PLDUX // mask pending_queries n a f i cs cnt_bits + s7 PUSH // mask pending_queries n a f i cs cnt_bits mask + AND // mask pending_queries n a f i cs _25 + IF:<{ // mask pending_queries n a f i cs + NEWC // mask pending_queries n a f i cs _27 + SWAP // mask pending_queries n a f i _27 cs + STSLICER // mask pending_queries n a f i _28 + s0 s0 s3 XCPUXC + 64 PUSHINT // mask pending_queries n i f _28 i a _29=64 + DICTUSETB // mask pending_queries n i f a + s0 s2 XCHG // mask pending_queries n a f i }>ELSE<{ - s1 s3 XCHG - DROP // mask n pending_queries i f a + DROP // mask pending_queries n a f i }> }>ELSE<{ - s1 s3 XCHG - DROP // mask n pending_queries i f a + DROP // mask pending_queries n a f i }> }>ELSE<{ - 2SWAP - DROP // mask n pending_queries i f a + s2 POP // mask pending_queries n a f i }> - SWAP // mask n pending_queries i a f - NOT // mask n pending_queries i a _28 - }> // mask n pending_queries i a + SWAP // mask pending_queries n a i f + NOT // mask pending_queries n a i _31 + s1 s2 XCHG // mask pending_queries n i a _31 + }> // mask pending_queries n i a s0 s4 XCHG 4 BLKDROP // a }> @@ -473,8 +577,9 @@ PROGRAM{ }> get_n_k PROC:<{ // - unpack_state INLINECALLDICT // _6 _7 _8 _9 _10 - 3 BLKDROP // n k + unpack_state INLINECALLDICT // _7 _8 _9 _10 _11 _12 + 3 BLKDROP + 1 2 BLKDROP2 // n k }> merge_inner_queries PROC:<{ // a b diff --git a/submodules/ton/tonlib-src/crypto/smartcont/auto/restricted-wallet-code.cpp b/submodules/ton/tonlib-src/crypto/smartcont/auto/restricted-wallet-code.cpp index 1391da27b8..327046a2b6 100644 --- a/submodules/ton/tonlib-src/crypto/smartcont/auto/restricted-wallet-code.cpp +++ b/submodules/ton/tonlib-src/crypto/smartcont/auto/restricted-wallet-code.cpp @@ -1 +1 @@ -with_tvm_code("restricted-wallet", "te6ccgECDQEAAQgAART/APSkE/Sg8sgLAQIBIAIDAgFIBAUB+vKDCNcYINMf0x/4IxK78mPtRNDTH9P/0VMxuvKhA54xMjL4AKTIyx/L/8ntVOED+QFUEEL5EPKi+ACA8/gzIG6SMH+X0NcLH/gjvOJx+DPQ1wv/BJMg10qOldMH1H8kjoUwUxbbPN6TAvsAkjIw4ugxMwLRpMjLH8v/ye1UDAICzgYHAgEgCgsCASAICQEBSAwAAwwgACUgPP4MyBukjB/l9DXCx/4I7zigABG+ZL9qJoa4WPwAOby2BAefwZkDdJGD/L6GuFj/wR3nFIuEp8EzeIcUADIB0NMDAXiwklt/4PpAMfpAMPpEAcD/Arqw"); +with_tvm_code("restricted-wallet", "te6ccgEBDAEA+wABFP8A9KQT9LzyyAsBAgEgAgMCAUgEBQL28oMI1xgg0x/TH/gjErvyY+1E0NMf0//RUzG68qEDnjFsIvgApMjLH8v/ye1U4QP5AVQQQvkQ8qL4AIDz+DMgbpIwf5fQ1wsf+CO84nH4M9DXC/8EkyDXSo6V0wfUfySOhTBTFts83pMC+wCSbCHi6DEzAtGkyMsfy//JCgsABNAwAgEgBgcCASAICQA5vLYEB5/BmQN0kYP8voa4WP/BHecUi4SnwTt4hxQAF7s5ztRNDTHzHXC/+AARuMl+1E0NcLH4ADIB0NMDAXiwklt/4PpAMfpAMPpEAcD/ArqwAATtVA=="); diff --git a/submodules/ton/tonlib-src/crypto/smartcont/auto/restricted-wallet-code.fif b/submodules/ton/tonlib-src/crypto/smartcont/auto/restricted-wallet-code.fif index 6582706c2b..3381cf16b0 100644 --- a/submodules/ton/tonlib-src/crypto/smartcont/auto/restricted-wallet-code.fif +++ b/submodules/ton/tonlib-src/crypto/smartcont/auto/restricted-wallet-code.fif @@ -5,6 +5,7 @@ PROGRAM{ DECLPROC check_destination DECLPROC recv_external 85143 DECLMETHOD seqno + 78748 DECLMETHOD get_public_key 104128 DECLMETHOD balance recv_internal PROC:<{ // in_msg @@ -71,8 +72,7 @@ PROGRAM{ s0 s3 XCHG // signature in_msg public_key cs stored_seqno msg_seqno IFNOTJMP:<{ // signature in_msg public_key cs stored_seqno NIP - s2 POP - s2 POP // public_key stored_seqno + 2 2 BLKDROP2 // public_key stored_seqno ACCEPT INC // public_key _35 NEWC // public_key _35 _36 @@ -110,8 +110,7 @@ PROGRAM{ s0 s2 XCHG // elector stored_seqno public_key restrict cs msg mode SENDRAWMSG }>ELSE<{ - s2 POP - DROP // elector stored_seqno public_key restrict cs + 2 1 BLKDROP2 // elector stored_seqno public_key restrict cs }> }> // elector stored_seqno public_key restrict cs NIP @@ -131,6 +130,14 @@ PROGRAM{ CTOS // _1 32 PLDU // _3 }> + get_public_key PROC:<{ + // + c4 PUSH // _1 + CTOS // cs + 32 LDU // _9 _8 + NIP // cs + 256 PLDU // _7 + }> balance PROC:<{ // restricted? INLINECALLDICT // _0 diff --git a/submodules/ton/tonlib-src/crypto/smartcont/auto/restricted-wallet2-code.cpp b/submodules/ton/tonlib-src/crypto/smartcont/auto/restricted-wallet2-code.cpp index a95ad749d2..dea7e2c94d 100644 --- a/submodules/ton/tonlib-src/crypto/smartcont/auto/restricted-wallet2-code.cpp +++ b/submodules/ton/tonlib-src/crypto/smartcont/auto/restricted-wallet2-code.cpp @@ -1 +1 @@ -with_tvm_code("restricted-wallet2", "te6ccgECDAEAAR0AART/APSkE/Sg8sgLAQIBIAIDAgFIBAUBAvIKAgLPBgcCASAICQADDCAAMyA8/gzIG6SMH+e+CMB0NcLH6GCAVGAqQTigABG+ZL9qJoa4WPwAf7y2B2omhAgJBrkPoCaMB5/BmQN0kYP898EYDoa4WP0MEAqMBUgnF8EzeIAUAIej230LfQmMv9ABhQuFsEyJhxQB/oMI1xgg0x/TH/gjErvyY+1E0NMf0//0BNFTQrryoQSOEjIzM/gAAaTIyx8Sy//0AMntVOEE+QFUEFT5EPKi+ACA8/gzIG6SMH+e+CMB0NcLH6GCAVGAqQTiIoAQ9HtvoW+hMZb6ADBy+wKRMOKTINdKltMH1AL7AOjRAqTIyx8LAA7L//QAye1U"); +with_tvm_code("restricted-wallet2", "te6ccgECCwEAAQgAART/APSkE/S88sgLAQIBIAIDAgFIBAUB+PKDCNcYINMf0x/4IxK78mPtRNDTH9P/9ATRU0K68qEEjhIyMzP4AAGkyMsfEsv/9ADJ7VThBPkBVBBU+RDyovgAgPP4MyBukjB/nvgjAdDXCx+hggFRgKkE4iKAEPR7b6UxlvoAMHL7ApEw4pMg10qW0wfUAvsA6NECpMgKAATQMAIBIAYHAgEgCAkAe7y2B2omhAgJBrkPoCaMB5/BmQN0kYP898EYDoa4WP0MEAqMBUgnF8E7eIAUAIej230pjL/QAYULhbBMiYcUABe7Oc7UTQ0x8x1wv/gAEbjJftRNDXCx+AASyx/L//QAye1U"); diff --git a/submodules/ton/tonlib-src/crypto/smartcont/auto/restricted-wallet2-code.fif b/submodules/ton/tonlib-src/crypto/smartcont/auto/restricted-wallet2-code.fif index 112e8c6228..18ffda9b63 100644 --- a/submodules/ton/tonlib-src/crypto/smartcont/auto/restricted-wallet2-code.fif +++ b/submodules/ton/tonlib-src/crypto/smartcont/auto/restricted-wallet2-code.fif @@ -4,6 +4,7 @@ PROGRAM{ DECLPROC days_passed DECLPROC recv_external 85143 DECLMETHOD seqno + 78748 DECLMETHOD get_public_key 104128 DECLMETHOD balance recv_internal PROC:<{ // in_msg @@ -74,8 +75,7 @@ PROGRAM{ s2 PUSH 16 PUSHINT // stored_seqno public_key rdict cs ts rdict _57=16 DICTIGETPREVEQ - NULLSWAPIFNOT - NULLSWAPIFNOT // stored_seqno public_key rdict cs _98 _97 _99 + NULLSWAPIFNOT2 // stored_seqno public_key rdict cs _98 _97 _99 NIP // stored_seqno public_key rdict cs value found IF:<{ // stored_seqno public_key rdict cs value LDGRAMS // stored_seqno public_key rdict cs _101 _100 @@ -110,6 +110,14 @@ PROGRAM{ CTOS // _1 32 PLDU // _3 }> + get_public_key PROC:<{ + // + c4 PUSH // _1 + CTOS // cs + 32 LDU // _9 _8 + NIP // cs + 256 PLDU // _7 + }> balance PROC:<{ // c4 PUSH // _1 @@ -124,8 +132,7 @@ PROGRAM{ s0 s2 XCHG 16 PUSHINT // balance ts rdict _19=16 DICTIGETPREVEQ - NULLSWAPIFNOT - NULLSWAPIFNOT // balance _29 _28 _30 + NULLSWAPIFNOT2 // balance _29 _28 _30 NIP // balance value found IF:<{ // balance value LDGRAMS // balance _32 _31 diff --git a/submodules/ton/tonlib-src/crypto/smartcont/auto/simple-wallet-code.cpp b/submodules/ton/tonlib-src/crypto/smartcont/auto/simple-wallet-code.cpp index ea4603f0ae..1bffadf5b5 100644 --- a/submodules/ton/tonlib-src/crypto/smartcont/auto/simple-wallet-code.cpp +++ b/submodules/ton/tonlib-src/crypto/smartcont/auto/simple-wallet-code.cpp @@ -1 +1 @@ -with_tvm_code("simple-wallet", "te6ccgEBBAEATwABFP8A9KQT9KDyyAsBAgEgAgMABNIwAG7ygwjXGCDTH+1E0NMf0//RUTG68qED+QFUEEL5EPKi+ABRINdKltMH1AL7AN7RpMjLH8v/ye1U"); +with_tvm_code("simple-wallet", "te6ccgEBBAEATwABFP8A9KQT9LzyyAsBAgEgAgMABNIwAG7ygwjXGCDTH+1E0NMf0//RUTG68qED+QFUEEL5EPKi+ABRINdKltMH1AL7AN7RpMjLH8v/ye1U"); diff --git a/submodules/ton/tonlib-src/crypto/smartcont/auto/simple-wallet-ext-code.cpp b/submodules/ton/tonlib-src/crypto/smartcont/auto/simple-wallet-ext-code.cpp index ad546b2894..3370e53e39 100644 --- a/submodules/ton/tonlib-src/crypto/smartcont/auto/simple-wallet-ext-code.cpp +++ b/submodules/ton/tonlib-src/crypto/smartcont/auto/simple-wallet-ext-code.cpp @@ -1 +1 @@ -with_tvm_code("simple-wallet-ext", "te6ccgEBFgEAzwABFP8A9KQT9KDyyAsBAgEgAgMCAUgEBQA08vACVDIS8AT4ACDXSpbTB9QC+wDe0aQB8AMCAs0GBwIBIA4PAgEgCAkAKdAUGEa4wQaY+CXXlQ/ICgCfyIeVFAIBIAoLAgEgDA0AAwwgAA8yBLLH8v/yYAARO1E0NMf0/8wgAAk8AHtVIAIBIBARAgEgFBUADbvtlwAfABgCASASEwARtZL9qJoa4WPwAA22l54AXgCQACG40BggFMl+1D2IIByODtQ9iAAVuI4MjLHxLLB8zJg="); +with_tvm_code("simple-wallet-ext", "te6ccgEBGAEA3AABFP8A9KQT9LzyyAsBAgEgAgMCAUgEBQA08vACVDIS8AT4ACDXSpbTB9QC+wDe0aQB8AMCAs0GBwIBIA4PAgEgCAkAKdAUGEa4wQaY+CXXlQ/ICgCfyIeVFAIBIAoLAgEgDA0AAwwgAA8AcjLH8v/yYAARO1E0NMf0/8wgAAk8AHtVIAIBIBARAgEgFhcCAW4SEwIBIBQVAAutzngBGMAADa9suAD4AMAAEbWS/aiaGuFj8AANtpeeAF4AkAAhuNAYIBTJftQ9iCAcjg7UPYgAFbiODIyx8SywfMyY"); diff --git a/submodules/ton/tonlib-src/crypto/smartcont/auto/simple-wallet-ext-code.fif b/submodules/ton/tonlib-src/crypto/smartcont/auto/simple-wallet-ext-code.fif index b403131e07..b7975e9480 100644 --- a/submodules/ton/tonlib-src/crypto/smartcont/auto/simple-wallet-ext-code.fif +++ b/submodules/ton/tonlib-src/crypto/smartcont/auto/simple-wallet-ext-code.fif @@ -7,14 +7,15 @@ PROGRAM{ DECLPROC do_verify_message DECLPROC recv_external 85143 DECLMETHOD seqno + 78748 DECLMETHOD get_public_key 81625 DECLMETHOD create_init_state 116960 DECLMETHOD prepare_send_message_with_seqno 101633 DECLMETHOD prepare_send_message 95420 DECLMETHOD verify_message create_state PROC:<{ // seqno public_key - NEWC // seqno public_key _2 - s1 s2 XCHG // public_key seqno _2 + SWAP + NEWC // public_key seqno _2 32 STU // public_key _4 256 STU // _6 ENDC // _7 @@ -76,6 +77,11 @@ PROGRAM{ CTOS // _1 32 PLDU // _3 }> + get_public_key PROC:<{ + // + load_state CALLDICT // _3 _4 + NIP // public_key + }> create_init_state PROC:<{ // public_key 0 PUSHINT // public_key _1=0 diff --git a/submodules/ton/tonlib-src/crypto/smartcont/auto/wallet-code.cpp b/submodules/ton/tonlib-src/crypto/smartcont/auto/wallet-code.cpp index 52fefeeb07..b706359e4f 100644 --- a/submodules/ton/tonlib-src/crypto/smartcont/auto/wallet-code.cpp +++ b/submodules/ton/tonlib-src/crypto/smartcont/auto/wallet-code.cpp @@ -1 +1 @@ -with_tvm_code("wallet", "te6ccgEBBgEAaAABFP8A9KQT9KDyyAsBAgEgAgMCAUgEBQCA8oMI1xgg0x/TH/gjErvyY+1E0NMf0//RUTG68qED+QFUEEL5EPKi+AACkyDXSpbTB9QC+wDo0aTIyx/L/8ntVAAE0DAAEaCZL9qJoa4WPw=="); +with_tvm_code("wallet", "te6ccgEBCAEAewABFP8A9KQT9LzyyAsBAgEgAgMCAUgEBQCA8oMI1xgg0x/TH/gjErvyY+1E0NMf0//RUTG68qED+QFUEEL5EPKi+AACkyDXSpbTB9QC+wDo0aTIyx/L/8ntVAAE0DACAUgGBwAXuznO1E0NMfMdcL/4ABG4yX7UTQ1wsfg="); diff --git a/submodules/ton/tonlib-src/crypto/smartcont/auto/wallet-code.fif b/submodules/ton/tonlib-src/crypto/smartcont/auto/wallet-code.fif index cd9fa5d0f8..4aa0cc0877 100644 --- a/submodules/ton/tonlib-src/crypto/smartcont/auto/wallet-code.fif +++ b/submodules/ton/tonlib-src/crypto/smartcont/auto/wallet-code.fif @@ -3,6 +3,7 @@ PROGRAM{ DECLPROC recv_internal DECLPROC recv_external 85143 DECLMETHOD seqno + 78748 DECLMETHOD get_public_key recv_internal PROC:<{ // in_msg DROP // @@ -56,4 +57,12 @@ PROGRAM{ CTOS // _1 32 PLDU // _3 }> + get_public_key PROC:<{ + // + c4 PUSH // _1 + CTOS // cs + 32 LDU // _9 _8 + NIP // cs + 256 PLDU // _7 + }> }END>c diff --git a/submodules/ton/tonlib-src/crypto/smartcont/auto/wallet3-code.cpp b/submodules/ton/tonlib-src/crypto/smartcont/auto/wallet3-code.cpp index 90e47b54d1..e5f46f8820 100644 --- a/submodules/ton/tonlib-src/crypto/smartcont/auto/wallet3-code.cpp +++ b/submodules/ton/tonlib-src/crypto/smartcont/auto/wallet3-code.cpp @@ -1 +1 @@ -with_tvm_code("wallet3", "te6ccgEBBgEAcwABFP8A9KQT9KDyyAsBAgEgAgMCAUgEBQCW8oMI1xgg0x/TH9Mf+CMTu/Jj7UTQ0x/TH9P/0VEyuvKhUUS68qIE+QFUEFX5EPKj+ACTINdKltMH1AL7AOgwAaTIyx/LH8v/ye1UAATQMAARoJkv2omhrhY/"); +with_tvm_code("wallet3", "te6ccgEBCAEAhgABFP8A9KQT9LzyyAsBAgEgAgMCAUgEBQCW8oMI1xgg0x/TH9Mf+CMTu/Jj7UTQ0x/TH9P/0VEyuvKhUUS68qIE+QFUEFX5EPKj+ACTINdKltMH1AL7AOgwAaTIyx/LH8v/ye1UAATQMAIBSAYHABe7Oc7UTQ0z8x1wv/gAEbjJftRNDXCx+A=="); diff --git a/submodules/ton/tonlib-src/crypto/smartcont/auto/wallet3-code.fif b/submodules/ton/tonlib-src/crypto/smartcont/auto/wallet3-code.fif index b0b45d7516..d539f3bad8 100644 --- a/submodules/ton/tonlib-src/crypto/smartcont/auto/wallet3-code.fif +++ b/submodules/ton/tonlib-src/crypto/smartcont/auto/wallet3-code.fif @@ -3,6 +3,7 @@ PROGRAM{ DECLPROC recv_internal DECLPROC recv_external 85143 DECLMETHOD seqno + 78748 DECLMETHOD get_public_key recv_internal PROC:<{ // in_msg DROP // @@ -62,4 +63,12 @@ PROGRAM{ CTOS // _1 32 PLDU // _3 }> + get_public_key PROC:<{ + // + c4 PUSH // _1 + CTOS // cs + 64 LDU // _9 _8 + NIP // cs + 256 PLDU // _7 + }> }END>c diff --git a/submodules/ton/tonlib-src/crypto/smartcont/config-code.fc b/submodules/ton/tonlib-src/crypto/smartcont/config-code.fc index 3a897d4cd0..15c87b3833 100644 --- a/submodules/ton/tonlib-src/crypto/smartcont/config-code.fc +++ b/submodules/ton/tonlib-src/crypto/smartcont/config-code.fc @@ -9,10 +9,9 @@ (cell, int, int, cell) load_data() inline { var cs = get_data().begin_parse(); - var (cfg_dict, stored_seqno, public_key) = (cs~load_ref(), cs~load_uint(32), cs~load_uint(256)); - var vote_dict = cs.slice_empty?() ? new_dict() : cs~load_dict(); + var res = (cs~load_ref(), cs~load_uint(32), cs~load_uint(256), cs~load_dict()); cs.end_parse(); - return (cfg_dict, stored_seqno, public_key, vote_dict); + return res; } () store_data(cfg_dict, stored_seqno, public_key, vote_dict) impure inline { @@ -26,7 +25,7 @@ (int, int) check_validator_set(cell vset) { var cs = vset.begin_parse(); - throw_if(9, (cs~load_uint(8) - 0x11) & -2); ;; validators#11 or validators_ext#12 + throw_unless(9, cs~load_uint(8) == 0x12); ;; validators_ext#12 only int utime_since = cs~load_uint(32); int utime_until = cs~load_uint(32); int total = cs~load_uint(16); @@ -103,7 +102,7 @@ .end_cell(), 0); } -() after_code_upgrade(slice param, cell old_code) impure method_id(1666) { +() after_code_upgrade(slice param, cont old_code) impure method_id(1666) { } _ perform_action(cfg_dict, public_key, action, cs) { @@ -119,7 +118,7 @@ _ perform_action(cfg_dict, public_key, action, cs) { var new_code = cs~load_ref(); set_code(new_code); var old_code = get_c3(); - set_c3(new_code); + set_c3(new_code.begin_parse().bless()); after_code_upgrade(cs, old_code); throw(0); return (cfg_dict, public_key); @@ -138,16 +137,21 @@ _ perform_action(cfg_dict, public_key, action, cs) { } } -slice get_validator_descr(int idx) inline_ref { +(slice, int) get_validator_descr(int idx) inline_ref { var vset = config_param(34); if (vset.null?()) { - return null(); + return (null(), 0); } var cs = begin_parse(vset); - cs~skip_bits(8 + 32 + 32 + 16 + 16); + ;; validators_ext#12 utime_since:uint32 utime_until:uint32 + ;; total:(## 16) main:(## 16) { main <= total } { main >= 1 } + ;; total_weight:uint64 + throw_unless(40, cs~load_uint(8) == 0x12); + cs~skip_bits(32 + 32 + 16 + 16); + int total_weight = cs~load_uint(64); var dict = begin_cell().store_slice(cs).end_cell(); var (value, _) = dict.udict_get?(16, idx); - return value; + return (value, total_weight); } (int, int) unpack_validator_descr(slice cs) inline { @@ -159,33 +163,51 @@ slice get_validator_descr(int idx) inline_ref { return (cs~load_uint(256), cs~load_uint(64)); } -slice create_new_entry(cs) inline { - return begin_cell().store_int(false, 1).store_uint(0, 64).store_uint(0, 256).store_slice(cs).end_cell().begin_parse(); +(cell, int, int, slice) new_proposal(cs) inline { + return (null(), 0, 0, cs); } -(cell, int, int, slice) unpack_suggestion(slice cs) inline { +(cell, int, int, slice) unpack_proposal(slice cs) inline { return (cs~load_dict(), cs~load_uint(64), cs~load_uint(256), cs); } -builder pack_suggestion(cell voters, int sum_weight, int vset_id, slice body) inline { +builder pack_proposal(cell voters, int sum_weight, int vset_id, slice body) inline { return begin_cell().store_dict(voters).store_uint(sum_weight, 64).store_uint(vset_id, 256).store_slice(body); } -cell register_vote(vote_dict, action, cs, idx, weight) { +(cell, slice) register_vote(vote_dict, action, cs, idx, weight, total_weight, cur_vset_id) { int hash = 0; + int found? = 0; var entry = null(); if (action & 1) { hash = slice_hash(cs); - (entry, var found?) = vote_dict.udict_get?(256, hash); - ifnot (found?) { - entry = create_new_entry(cs); - } + (entry, found?) = vote_dict.udict_get?(256, hash); } else { hash = cs.preload_uint(256); - (entry, var found?) = vote_dict.udict_get?(256, hash); + (entry, found?) = vote_dict.udict_get?(256, hash); throw_unless(42, found?); } - return vote_dict; + var (voters, sum_weight, vset_id, body) = found? ? unpack_proposal(entry) : (null(), 0, cur_vset_id, cs); + if (vset_id != cur_vset_id) { + voters = null(); + sum_weight = 0; + vset_id = cur_vset_id; + } + var (_, found?) = voters.udict_get?(16, idx); + ifnot (found?) { + voters~udict_set_builder(16, idx, begin_cell().store_uint(32, now())); + sum_weight += weight; + if (sum_weight * 3 > total_weight * 2) { + ;; proposal accepted + vote_dict~udict_delete?(256, hash); + return (vote_dict, body); + } else { + vote_dict~udict_set_builder(256, hash, pack_proposal(voters, sum_weight, cur_vset_id, body)); + return (vote_dict, null()); + } + } else { + return (vote_dict, null()); + } } () recv_external(slice in_msg) impure { @@ -199,15 +221,19 @@ cell register_vote(vote_dict, action, cs, idx, weight) { throw_unless(33, msg_seqno == stored_seqno); ifnot ((action - 0x566f7465) & -2) { var idx = cs~load_uint(16); - var vdescr = get_validator_descr(idx); + var (vdescr, total_weight) = get_validator_descr(idx); var (val_pubkey, weight) = unpack_validator_descr(vdescr); throw_unless(34, check_signature(slice_hash(in_msg), signature, val_pubkey)); accept_message(); stored_seqno += 1; store_data(cfg_dict, stored_seqno, public_key, vote_dict); commit(); - vote_dict = register_vote(vote_dict, action, cs, idx, weight); + (vote_dict, var accepted) = register_vote(vote_dict, action, cs, idx, weight, total_weight, config_param(34).cell_hash()); store_data(cfg_dict, stored_seqno, public_key, vote_dict); + ifnot (accepted.null?()) { + (cfg_dict, public_key) = perform_action(cfg_dict, public_key, accepted~load_uint(32), accepted); + store_data(cfg_dict, stored_seqno, public_key, vote_dict); + } return (); } throw_unless(34, check_signature(slice_hash(in_msg), signature, public_key)); @@ -231,7 +257,7 @@ cell register_vote(vote_dict, action, cs, idx, weight) { if (ds.slice_bits() >= 40) { var tag = ds~load_uint(8); var since = ds.preload_uint(32); - if ((tag == 0x11) & (since >= now())) { + if ((since <= now()) & (tag == 0x12)) { ;; next validator set becomes active! var cur_vset = cfg_dict~idict_set_get_ref(kl, 34, next_vset); ;; next_vset -> cur_vset cfg_dict~idict_set_get_ref(kl, 32, cur_vset); ;; cur_vset -> prev_vset @@ -241,3 +267,7 @@ cell register_vote(vote_dict, action, cs, idx, weight) { } set_data(begin_cell().store_ref(cfg_dict).store_slice(cs).end_cell()); } + +int seqno() impure method_id { + return get_data().begin_parse().preload_uint(32); +} diff --git a/submodules/ton/tonlib-src/crypto/smartcont/dns-auto-code.fc b/submodules/ton/tonlib-src/crypto/smartcont/dns-auto-code.fc new file mode 100644 index 0000000000..e548a70a07 --- /dev/null +++ b/submodules/ton/tonlib-src/crypto/smartcont/dns-auto-code.fc @@ -0,0 +1,514 @@ +{- + Adapted from original version written by: + /------------------------------------------------------------------------\ + | Created for: Telegram (Open Network) Blockchain Contest | + | Task 2: DNS Resolver (Automatically registering) | + >------------------------------------------------------------------------< + | Author: Oleksandr Murzin (tg: @skydev / em: alexhacker64@gmail.com) | + | October 2019 | + \------------------------------------------------------------------------/ +-} + +;;===========================================================================;; +;; Utility functions ;; +;;===========================================================================;; + +{- + Data structure: + Root cell: [OptRef<1b+1r?>:HashmapUInt<32b>,CatTable>:domains] + [OptRef<1b+1r?>:Hashmap(Time|Hash128)->Slice(DomName)>:gc] + [UInt<32b>:stdperiod] [Gram:PPReg] [Gram:PPCell] [Gram:PPBit] + [UInt<32b>:lasthousekeeping] + := HashmapE 16 ^DNSRecord + + STORED DOMAIN NAME SLICE FORMAT: (#ZeroChars<7b>) (Domain name value) + #Zeros allows to simultaneously store, for example, com\0 and com\0google\0 + That will be stored as \1com\0 and \2com\0google\0 (pfx tree has restricitons) + This will allow to resolve more specific requests to subdomains, and resort + to parent domain next resolver lookup if subdomain is not found + com\0goo\0 lookup will, for example look up \2com\0goo\0 and then + \1com\0goo\0 which will return \1com\0 (as per pfx tree) with -1 cat +-} + +(cell, cell, cell, [int, int, int, int], int, int) load_data() inline_ref { + slice cs = get_data().begin_parse(); + return ( + cs~load_ref(), ;; control data + cs~load_dict(), ;; pfx tree: domains data and exp + cs~load_dict(), ;; gc auxillary with expiration and 128-bit hash slice + [ cs~load_uint(30), ;; length of this period of time in seconds + cs~load_grams(), ;; standard payment for registering a new subdomain + cs~load_grams(), ;; price paid for each cell (PPC) + cs~load_grams() ], ;; and bit (PPB) + cs~load_uint(32), ;; next housekeeping to be done at + cs~load_uint(32) ;; last housekeeping done at + ); +} + +(int, int, int, int) load_prices() inline_ref { + slice cs = get_data().begin_parse(); + (cs~load_ref(), cs~load_dict(), cs~load_dict()); + return (cs~load_uint(30), cs~load_grams(), cs~load_grams(), cs~load_grams()); +} + +() store_data(cell ctl, cell dd, cell gc, prices, int nhk, int lhk) impure { + var [sp, ppr, ppc, ppb] = prices; + set_data(begin_cell() + .store_ref(ctl) ;; control data + .store_dict(dd) ;; domains data and exp + .store_dict(gc) ;; keyed expiration time and 128-bit hash slice + .store_uint(sp, 30) ;; standard period + .store_grams(ppr) ;; price per registration + .store_grams(ppc) ;; price per cell + .store_grams(ppb) ;; price per bit + .store_uint(nhk, 32) ;; next housekeeping + .store_uint(lhk, 32) ;; last housekeeping + .end_cell()); +} + +global var query_info; + +() send_message(slice addr, int tag, int query_id, + int body, int grams, int mode) impure { + ;; int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool + ;; src:MsgAddress -> 011000 0x18 + var msg = begin_cell() + .store_uint (0x18, 6) + .store_slice(addr) + .store_grams(grams) + .store_uint (0, 1 + 4 + 4 + 64 + 32 + 1 + 1) + .store_uint (tag, 32) + .store_uint (query_id, 64); + if (body >= 0) { + msg~store_uint(body, 32); + } + send_raw_message(msg.end_cell(), mode); +} + +() send_error(int error_code) impure { + var (addr, query_id, op) = query_info; + return send_message(addr, error_code, query_id, op, 0, 64); +} + +() send_ok(int price) impure { + raw_reserve(price, 4); + var (addr, query_id, op) = query_info; + return send_message(addr, 0xef6b6179, query_id, op, 0, 128); +} + +() housekeeping(cell ctl, cell dd, cell gc, prices, int nhk, int lhk, int max_steps) impure { + int n = now(); + if (n < max(nhk, lhk + 60)) { ;; housekeeping cooldown: 1 minute + ;; if housekeeping was done recently, or if next housekeeping is in the future, just save + return store_data(ctl, dd, gc, prices, nhk, lhk); + } + ;; need to do some housekeeping - maybe remove entry with + ;; least expiration but only if it is already expired + ;; no iterating and deleting all to not put too much gas gc + ;; burden on any random specific user request + ;; over time it will do the garbage collection required + (int mkey, _, int found?) = gc.udict_get_min?(256); + while (found? & max_steps) { ;; no short circuit optimization, two nested ifs + nhk = (mkey >> (256 - 32)); + if (nhk < n) { + int key = mkey % (1 << (256 - 32)); + (slice val, found?) = dd.udict_get?(256 - 32, key); + if (found?) { + int exp = val.preload_uint(32); + if (exp <= n) { + dd~udict_delete?(256 - 32, key); + } + } + gc~udict_delete?(256, mkey); + (mkey, _, found?) = gc.udict_get_min?(256); + nhk = (found? ? mkey >> (256 - 32) : 0xffffffff); + max_steps -= 1; + } else { + found? = false; + } + } + store_data(ctl, dd, gc, prices, nhk, n); +} + +int calcprice_internal(slice domain, cell data, ppc, ppb) inline_ref { ;; only for internal calcs + var (_, bits, refs) = compute_data_size(data, 100); ;; 100 cells max + bits += slice_bits(domain) * 2 + (128 + 32 + 32); + return ppc * (refs + 2) + ppb * bits; +} + +int check_owner(cell cat_table, cell owner_info, int src_wc, int src_addr, int strict) inline_ref { + if (strict & cat_table.null?()) { ;; domain not found: return notf | 2^31 + return 0xee6f7466; + } + if (owner_info.null?()) { ;; no owner on this domain: no-2 (in strict mode), ok else + return strict & 0xee6f2d32; + } + var ERR_BAD2 = 0xe2616432; + slice sown = owner_info.begin_parse(); + if (sown.slice_bits() < 16 + 3 + 8 + 256) { ;; bad owner record: bad2 + return ERR_BAD2; + } + if (sown~load_uint(16 + 3) != 0x9fd3 * 8 + 4) { + return ERR_BAD2; + } + (int owner_wc, int owner_addr) = (sown~load_int(8), sown.preload_uint(256)); + if ((owner_wc != src_wc) | (owner_addr != src_addr)) { ;; not owner: nown + return 0xee6f776e; + } + return 0; ;; ok +} + +;;===========================================================================;; +;; Internal message handler (Code 0) ;; +;;===========================================================================;; + +{- + Internal message cell structure: + 8 4 2 1 + int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool + src:MsgAddressInt dest:MsgAddressInt + value:CurrencyCollection ihr_fee:Grams fwd_fee:Grams + created_lt:uint64 created_at:uint32 + Internal message data structure: + [UInt<32b>:op] [UInt<64b>:query_id] [Ref<1r>:domain] + (if not prolong: [Ref<1r>:value->CatTable]) + +-} + +;; Control operations: permitted only to the owner of this smartcontract +() perform_ctl_op(int op, int src_wc, int src_addr, slice in_msg) impure inline_ref { + var (ctl, domdata, gc, prices, nhk, lhk) = load_data(); + var cs = ctl.begin_parse(); + if ((cs~load_int(8) != src_wc) | (cs~load_uint(256) != src_addr)) { + return send_error(0xee6f776e); + } + if (op == 0x43685072) { ;; ChPr = Change Prices + var (stdper, ppr, ppc, ppb) = (in_msg~load_uint(32), in_msg~load_grams(), in_msg~load_grams(), in_msg~load_grams()); + in_msg.end_parse(); + ;; NB: stdper == 0 -> disable new actions + store_data(ctl, domdata, gc, [stdper, ppr, ppc, ppb], nhk, lhk); + return send_ok(0); + } + if (op == 0x4344656c) { ;; CDel = destroy smart contract + ifnot (domdata.null?()) { + ;; domain dictionary not empty, force gc + housekeeping(ctl, domdata, gc, prices, nhk, 1, -1); + } + (ctl, domdata, gc, prices, nhk, lhk) = load_data(); + ifnot (domdata.null?()) { + ;; domain dictionary still not empty, error + return send_error(0xee74656d); + } + var (addr, query_id, op) = query_info; + return send_message(addr, 0xef6b6179, query_id, op, 0, 128 + 32); + } + return send_error(0xffffffff); +} + +;; Must send at least GR$1 more for possible gas fees! +() recv_internal(int msg_value, cell in_msg_cell, slice in_msg) impure { + ;; this time very interested in internal messages + if (in_msg.slice_bits() < 32) { + return (); ;; simple transfer or short + } + slice cs = in_msg_cell.begin_parse(); + int flags = cs~load_uint(4); + if (flags & 1) { + return (); ;; bounced messages + } + slice s_addr = cs~load_msg_addr(); + (int src_wc, int src_addr) = s_addr.parse_std_addr(); + int op = in_msg~load_uint(32); + ifnot (op) { + return (); ;; simple transfer with comment + } + int query_id = 0; + if (in_msg.slice_bits() >= 64) { + query_id = in_msg~load_uint(64); + } + + query_info = (s_addr, query_id, op); + + if (op & (1 << 31)) { + return (); ;; an answer to our query + } + if ((op >> 24) == 0x43) { + ;; Control operations + return perform_ctl_op(op, src_wc, src_addr, in_msg); + } + + int qt = (op == 0x72656764) * 1 + (op == 0x70726f6c) * 2 + (op == 0x75706464) * 4 + (op == 0x676f6763) * 8; + ifnot (qt) { ;; unknown query, return error + return send_error(0xffffffff); + } + qt = - qt; + + (cell ctl, cell domdata, cell gc, [int, int, int, int] prices, int nhk, int lhk) = load_data(); + + if (qt == 8) { ;; 0x676f6763 -> GO, GC! go!!! + ;; Manual garbage collection iteration + int max_steps = in_msg~load_int(32); ;; -1 = infty + housekeeping(ctl, domdata, gc, prices, nhk, 1, max_steps); ;; forced + return send_error(0xef6b6179); + } + + slice domain = null(); + cell domain_cell = in_msg~load_maybe_ref(); + int fail = 0; + if (domain_cell.null?()) { + int bytes = in_msg~load_uint(6); + fail = (bytes == 0); + domain = in_msg~load_bits(bytes * 8); + } else { + domain = domain_cell.begin_parse(); + var (bits, refs) = slice_bits_refs(domain); + fail = (refs | ((bits - 8) & (7 - 128))); + } + + ifnot (fail) { + ;; domain must end with \0! no\0 error + fail = domain.slice_last(8).preload_uint(8); + } + if (fail) { + return send_error(0xee6f5c30); + } + + int n = now(); + cell cat_table = cell owner_info = null(); + int key = int exp = int zeros = 0; + slice tail = domain; + repeat (tail.slice_bits() ^>> 3) { + cat_table = null(); + int z = (tail~load_uint(8) == 0); + zeros -= z; + if (z) { + key = (string_hash(domain.skip_last_bits(tail.slice_bits())) >> 32); + var (val, found?) = domdata.udict_get?(256 - 32, key); + if (found?) { + exp = val~load_uint(32); + if (exp >= n) { ;; entry not expired + cell cat_table = val~load_ref(); + val.end_parse(); + var (cown, ok) = cat_table.idict_get_ref?(16, -2); + if (ok) { + owner_info = cown; + } + } + } + } + } + + if (zeros > 4) { ;; too much zero chars (overflow): ov\0 + return send_error(0xef765c30); + } + + ;; ########################################################################## + + int err = check_owner(cat_table, owner_info, src_wc, src_addr, qt != 1); + if (err) { + return send_error(err); + } + + ;; ########################################################################## + + ;; load desired data (reuse old for a "prolong" operation) + cell data = null(); + + if (qt != 2) { ;; not a "prolong", load data dictionary + data = in_msg~load_ref(); + ;; basic integrity check of (client-provided) dictionary + ifnot (data.dict_empty?()) { ;; 1000 gas! + var (oinfo, ok) = data.idict_get_ref?(16, -2); + if (ok) { + var cs = oinfo.begin_parse(); + throw_unless(31, cs.slice_bits() >= 16 + 3 + 8 + 256); + throw_unless(31, cs.preload_uint(19) == 0x9fd3 * 8 + 4); + } + (_, _, int minok) = data.idict_get_min?(16); + (_, _, int maxok) = data.idict_get_max?(16); + throw_unless(31, minok & maxok); + } + } else { + data = cat_table; + } + + ;; load prices + var [stdper, ppr, ppc, ppb] = prices; + ifnot (stdper) { ;; smart contract disabled by owner, no new actions + return send_error(0xd34f4646); + } + + ;; compute action price + int price = calcprice_internal(domain, data, ppc, ppb) + (ppr & (qt != 4)); + if (msg_value - (1 << 30) < price) { ;; gr prol | prolong domain + if (exp > n + stdper) { ;; does not expire soon, cannot prolong + return send_error(0xf365726f); + } + domdata~udict_set_builder(256 - 32, key, begin_cell().store_uint(exp + stdper, 32).store_ref(data)); + + int gckeyO = (exp << (256 - 32)) + key; + int gckeyN = gckeyO + (stdper << (256 - 32)); + gc~udict_delete?(256, gckeyO); ;; delete old gc entry, add new + gc~udict_set_builder(256, gckeyN, begin_cell()); + + housekeeping(ctl, domdata, gc, prices, nhk, lhk, 1); + return send_ok(price); + } + + ;; ########################################################################## + if (qt == 1) { ;; 0x72656764 -> regd | register domain + ifnot (cat_table.null?()) { ;; domain already exists: return alre | 2^31 + return send_error(0xe16c7265); + } + int expires_at = n + stdper; + domdata~udict_set_builder(256 - 32, key, begin_cell().store_uint(expires_at, 32).store_ref(data)); + + int gckey = (expires_at << (256 - 32)) | key; + gc~udict_set_builder(256, gckey, begin_cell()); + + housekeeping(ctl, domdata, gc, prices, min(nhk, expires_at), lhk, 1); + return send_ok(price); + } + + ;; ########################################################################## + if (qt == 4) { ;; 0x75706464 -> updd | update domain (data) + domdata~udict_set_builder(256 - 32, key, begin_cell().store_uint(exp, 32).store_ref(data)); + housekeeping(ctl, domdata, gc, prices, nhk, lhk, 1); + return send_ok(price); + } + ;; ########################################################################## + + return (); ;; should NEVER reach this part of code! +} + +;;===========================================================================;; +;; External message handler (Code -1) ;; +;;===========================================================================;; + +() recv_external(slice in_msg) impure { + ;; only for initialization + (cell ctl, cell dd, cell gc, var prices, int nhk, int lhk) = load_data(); + ifnot (lhk) { + accept_message(); + return store_data(ctl, dd, gc, prices, 0xffffffff, now()); + } +} + +;;===========================================================================;; +;; Getter methods ;; +;;===========================================================================;; + +(int, cell, int, slice) dnsdictlookup(slice domain, int nowtime) inline_ref { + (int bits, int refs) = domain.slice_bits_refs(); + throw_if(30, refs | (bits & 7)); ;; malformed input (~ 8n-bit) + ifnot (bits) { + return (0, null(), 0, null()); ;; zero-length input + } + + int domain_last_byte = domain.slice_last(8).preload_uint(8); + if (domain_last_byte) { + domain = begin_cell().store_slice(domain) ;; append zero byte + .store_uint(0, 8).end_cell().begin_parse(); + bits += 8; + } + if (bits == 8) { + return (0, null(), 0, null()); ;; zero-length input, but with zero byte + } + var ds = get_data().begin_parse(); + (_, cell root) = (ds~load_ref(), ds~load_dict()); + + slice val = null(); + int tail_bits = -1; + slice tail = domain; + + repeat (bits >> 3) { + if (tail~load_uint(8) == 0) { + var key = (string_hash(domain.skip_last_bits(tail.slice_bits())) >> 32); + var (v, found?) = root.udict_get?(256 - 32, key); + if (found?) { + if (v.preload_uint(32) >= nowtime) { ;; entry not expired + val = v; + tail_bits = tail.slice_bits(); + } + } + } + } + + if (val.null?()) { + return (0, null(), 0, null()); ;; failed to find entry in subdomain dictionary + } + + return (val~load_uint(32), val~load_ref(), tail_bits == 0, domain.skip_last_bits(tail_bits)); +} + +;;8m dns-record-value +(int, cell) dnsresolve(slice domain, int category) method_id { + (int exp, cell cat_table, int exact?, slice pfx) = dnsdictlookup(domain, now()); + ifnot (exp) { + return (0, null()); + } + ifnot (exact?) { ;; incomplete subdomain found, must return next resolver (-1) + category = -1; + } + + int pfx_bits = pfx.slice_bits(); + + ;; pfx.slice_bits() will contain 8m, where m is number of bytes in subdomain + ;; COUNTING the zero byte (if structurally correct: no multiple-ZB keys) + ;; which corresponds to 8m, m=one plus the number of bytes in the subdomain found) + ifnot (category) { + return (pfx_bits, cat_table); ;; return cell with entire dictionary for 0 + } else { + cell cat_found = cat_table.idict_get_ref(16, category); + return (pfx_bits, cat_found); + } +} + +;; getexpiration needs to know the current time to skip any possible expired +;; subdomains in the chain. it will return 0 if not found or expired. +int getexpirationx(slice domain, int nowtime) inline method_id { + (int exp, _, _, _) = dnsdictlookup(domain, nowtime); + return exp; +} + +int getexpiration(slice domain) method_id { + return getexpirationx(domain, now()); +} + +int getstdperiod() method_id { + (int stdper, _, _, _) = load_prices(); + return stdper; +} + +int getppr() method_id { + (_, int ppr, _, _) = load_prices(); + return ppr; +} + +int getppc() method_id { + (_, _, int ppc, _) = load_prices(); + return ppc; +} + +int getppb() method_id { + ( _, _, _, int ppb) = load_prices(); + return ppb; +} + +int calcprice(slice domain, cell val) method_id { ;; only for external gets (not efficient) + (_, _, int ppc, int ppb) = load_prices(); + return calcprice_internal(domain, val, ppc, ppb); +} + +int calcregprice(slice domain, cell val) method_id { ;; only for external gets (not efficient) + (_, int ppr, int ppc, int ppb) = load_prices(); + return ppr + calcprice_internal(domain, val, ppc, ppb); +} diff --git a/submodules/ton/tonlib-src/crypto/smartcont/dns-manual-code.fc b/submodules/ton/tonlib-src/crypto/smartcont/dns-manual-code.fc new file mode 100644 index 0000000000..890d5d86fa --- /dev/null +++ b/submodules/ton/tonlib-src/crypto/smartcont/dns-manual-code.fc @@ -0,0 +1,348 @@ +{- + Originally created by: + /------------------------------------------------------------------------\ + | Created for: Telegram (Open Network) Blockchain Contest | + | Task 3: DNS Resolver (Manually controlled) | + >------------------------------------------------------------------------< + | Author: Oleksandr Murzin (tg: @skydev / em: alexhacker64@gmail.com) | + | October 2019 | + \------------------------------------------------------------------------/ +-} + +;;===========================================================================;; +;; Custom ASM instructions ;; +;;===========================================================================;; + +(cell, ()) pfxdict_set_ref(cell dict, int key_len, slice key, cell value) { + throw_unless(33, dict~pfxdict_set?(key_len, key, begin_cell().store_maybe_ref(value).end_cell().begin_parse())); + return (dict, ()); +} + +(slice, cell, slice, int) pfxdict_get_ref(cell dict, int key_len, slice key) inline_ref { + (slice pfx, slice val, slice tail, int succ) = dict.pfxdict_get?(key_len, key); + cell res = succ ? val~load_maybe_ref() : null(); + return (pfx, res, tail, succ); +} + +;;===========================================================================;; +;; Utility functions ;; +;;===========================================================================;; + +(int, int, int, cell, cell) load_data() inline_ref { + slice cs = get_data().begin_parse(); + var res = (cs~load_uint(32), cs~load_uint(64), cs~load_uint(256), cs~load_dict(), cs~load_dict()); + cs.end_parse(); + return res; +} + +() store_data(int contract_id, int last_cleaned, int public_key, cell root, old_queries) impure { + set_data(begin_cell() + .store_uint(contract_id, 32) + .store_uint(last_cleaned, 64) + .store_uint(public_key, 256) + .store_dict(root) + .store_dict(old_queries) + .end_cell()); +} + +;;===========================================================================;; +;; Internal message handler (Code 0) ;; +;;===========================================================================;; + +() recv_internal(int msg_value, cell in_msg_cell, slice in_msg) impure { + ;; not interested at all +} + +;;===========================================================================;; +;; External message handler (Code -1) ;; +;;===========================================================================;; + +{- + External message structure: + [Bytes<512b>:signature] [UInt<32b>:seqno] [UInt<6b>:operation] + [Either b0: inline name (<= 58-x Bytes) or b1: reference-stored name) + x depends on operation + Use of 6-bit op instead of 32-bit allows to save 4 bytes for inline name + Inline [Name] structure: [UInt<6b>:length] [Bytes:data] + Operations (continuation of message): + 00 Contract initialization message (only if seqno = 0) (x=-) + 11 VSet: set specified value to specified subdomain->category (x=2) + [Int<16b>:category] [Name:subdomain] [Cell<1r>:value] + 12 VDel: delete specified subdomain->category (x=2) + [Int<16b>:category] [Name:subdomain] + 21 DSet: replace entire category dictionary of domain with provided (x=0) + [Name:subdomain] [Cell<1r>:new_cat_table] + 22 DDel: delete entire category dictionary of specified domain (x=0) + [Name:subdomain] + 31 TSet: replace ENTIRE DOMAIN TABLE with the provided tree root cell (x=-) + [Cell<1r>:new_domains_table] + 32 TDel: nullify ENTIRE DOMAIN TABLE (x=-) + 51 OSet: replace owner public key with a new one (x=-) + [UInt<256b>:new_public_key] +-} + +() after_code_upgrade(cell root, slice ops, cont old_code) impure method_id(1666); + +(cell, slice) process_op(cell root, slice ops) inline_ref { + int op = ops~load_uint(6); + if (op < 10) { + ifnot (op) { + ;; 00 Noop: No operation + return (root, ops); + } + if (op == 1) { + ;; 01 SMsg: Send Message + var mode = ops~load_uint(8); + send_raw_message(ops~load_ref(), mode); + return (root, ops); + } + if (op == 9) { + ;; 09 CodeUpgrade + var new_code = ops~load_ref(); + set_code(new_code); + var old_code = get_c3(); + set_c3(new_code.begin_parse().bless()); + after_code_upgrade(root, ops, old_code); + throw(0); + return (root, ops); + } + throw(45); + return (root, ops); + } + int cat = 0; + if (op < 20) { + ;; for operations with codes 10..19 category is required + cat = ops~load_int(16); + } + slice name = null(); ;; any slice value + cell cat_table = null(); + if (op < 30) { + ;; for operations with codes 10..29 name is required + int is_name_ref = (ops~load_uint(1) == 1); + if (is_name_ref) { + ;; name is stored in separate referenced cell + name = ops~load_ref().begin_parse(); + } else { + ;; name is stored inline + int name_len = ops~load_uint(6) * 8; + name = ops~load_bits(name_len); + } + ;; at least one character not counting \0 + throw_unless(38, name.slice_bits() >= 16); + ;; name shall end with \0 + int name_last_byte = name.slice_last(8).preload_uint(8); + throw_if(40, name_last_byte); + ;; count zero separators + int zeros = 0; + slice cname = name; + repeat (cname.slice_bits() ^>> 3) { + int c = cname~load_uint(8); + zeros -= (c == 0); + } + ;; throw_unless(39, zeros == 1); + name = begin_cell().store_uint(zeros, 7).store_slice(name).end_cell().begin_parse(); + } + ;; operation with codes 10..19 manipulate category dict + ;; lets try to find it and store into a variable + ;; operations with codes 20..29 replace / delete dict, no need + if (op < 20) { + ;; lets resolve the name here so as not to duplicate the code + (slice pfx, cell val, slice tail, int succ) = + root.pfxdict_get_ref(1023, name); + if (succ) { + ;; must match EXACTLY to prevent accident changes + throw_unless(35, tail.slice_empty?()); + cat_table = val; + } + ;; otherwise cat_table is null which is reasonable for actions + } + ;; 11 VSet: set specified value to specified subdomain->category + if (op == 11) { + cell new_value = ops~load_maybe_ref(); + cat_table~idict_set_get_ref(16, cat, new_value); + root~pfxdict_set_ref(1023, name, cat_table); + return (root, ops); + } + ;; 12 VDel: delete specified subdomain->category value + if (op == 12) { + if (cat_table~idict_delete?(16, cat)) { + root~pfxdict_set_ref(1023, name, cat_table); + } + return (root, ops); + } + ;; 21 DSet: replace entire category dictionary of domain with provided + if (op == 21) { + cell new_cat_table = ops~load_maybe_ref(); + root~pfxdict_set_ref(1023, name, new_cat_table); + return (root, ops); + } + ;; 22 DDel: delete entire category dictionary of specified domain + if (op == 22) { + root~pfxdict_delete?(1023, name); + return (root, ops); + } + ;; 31 TSet: replace ENTIRE DOMAIN TABLE with the provided tree root cell + if (op == 31) { + cell new_tree_root = ops~load_maybe_ref(); + ;; no sanity checks cause they would cost immense gas + return (new_tree_root, ops); + } + ;; 32 TDel: nullify ENTIRE DOMAIN TABLE + if (op == 32) { + return (null(), ops); + } + throw(44); ;; invalid operation + return (null(), ops); +} + +cell process_ops(cell root, slice ops) inline_ref { + var stop = false; + root~touch(); + ops~touch(); + do { + (root, ops) = process_op(root, ops); + if (ops.slice_data_empty?()) { + if (ops.slice_refs()) { + ops = ops~load_ref().begin_parse(); + } else { + stop = true; + } + } + } until (stop); + return root; +} + +() recv_external(slice in_msg) impure { + ;; Load data + (int contract_id, int last_cleaned, int public_key, cell root, cell old_queries) = load_data(); + + ;; validate signature and seqno + slice signature = in_msg~load_bits(512); + int shash = slice_hash(in_msg); + var (query_contract, query_id) = (in_msg~load_uint(32), in_msg~load_uint(64)); + var bound = (now() << 32); + throw_if(35, query_id < bound); + (_, var found?) = old_queries.udict_get?(64, query_id); + throw_if(32, found?); + throw_unless(34, contract_id == query_contract); + throw_unless(35, check_signature(shash, signature, public_key)); + accept_message(); ;; message is signed by owner, sanity not guaranteed yet + + int op = in_msg.preload_uint(6); + if (op == 51) { + in_msg~skip_bits(6); + public_key = in_msg~load_uint(256); + } else { + root = process_ops(root, in_msg); + } + + bound -= (64 << 32); ;; clean up records expired more than 64 seconds ago + old_queries~udict_set_builder(64, query_id, begin_cell()); + var queries = old_queries; + do { + var (old_queries', i, _, f) = old_queries.udict_delete_get_min(64); + f~touch(); + if (f) { + f = (i < bound); + } + if (f) { + old_queries = old_queries'; + last_cleaned = i; + } + } until (~ f); + + store_data(contract_id, last_cleaned, public_key, root, old_queries); +} + +() after_code_upgrade(cell root, slice ops, cont old_code) impure method_id(1666) { +} + +{- + Data structure: + Root cell: [UInt<32b>:seqno] [UInt<256b>:owner_public_key] + [OptRef<1b+1r?>:HashmapCatTable>:domains] + := HashmapE 16 ^DNSRecord + + STORED DOMAIN NAME SLICE FORMAT: (#ZeroChars<7b>) (Domain name value) + #Zeros allows to simultaneously store, for example, com\0 and com\0google\0 + That will be stored as \1com\0 and \2com\0google\0 (pfx tree has restricitons) + This will allow to resolve more specific requests to subdomains, and resort + to parent domain next resolver lookup if subdomain is not found + com\0goo\0 lookup will, for example look up \2com\0goo\0 and then + \1com\0goo\0 which will return \1com\0 (as per pfx tree) with -1 cat +-} + +;;===========================================================================;; +;; Getter methods ;; +;;===========================================================================;; + +;; Retrieve contract id (in case several contracts are managed with the same private key) +int get_contract_id() method_id { + return get_data().begin_parse().preload_uint(32); +} + +int get_public_key() method_id { + var cs = get_data().begin_parse(); + cs~load_uint(32 + 64); + return cs.preload_uint(256); +} + +;;8m dns-record-value +(int, cell) dnsresolve(slice subdomain, int category) method_id { + int bits = subdomain.slice_bits(); + ifnot (bits) { + return (0, null()); ;; zero-length input + } + throw_if(30, bits & 7); ;; malformed input (~ 8n-bit) + + int name_last_byte = subdomain.slice_last(8).preload_uint(8); + if (name_last_byte) { + subdomain = begin_cell().store_slice(subdomain) ;; append zero byte + .store_uint(0, 8).end_cell().begin_parse(); + bits += 8; + } + if (bits == 8) { + return (0, null()); ;; zero-length input, but with zero byte + } + (_, _, _, cell root, _) = load_data(); + + slice cname = subdomain; + int zeros = 0; + repeat (bits >> 3) { + int c = cname~load_uint(8); + zeros -= (c == 0); + } + + ;; can't move these declarations lower, will cause errors! + slice pfx = cname; + cell val = null(); + slice tail = cname; + + do { + slice pfxname = begin_cell().store_uint(zeros, 7) + .store_slice(subdomain).end_cell().begin_parse(); + (pfx, val, tail, int succ) = root.pfxdict_get_ref(1023, pfxname); + zeros = succ ^ (zeros - 1); ;; break on success + } until (zeros <= 0); + + ifnot (zeros) { + return (0, null()); ;; failed to find entry in prefix dictionary + } + + zeros = - zeros; + + ifnot (tail.slice_empty?()) { ;; if we have tail then len(pfx) < len(subdomain) + category = -1; ;; incomplete subdomain found, must return next resolver (-1) + } + int pfx_bits = pfx.slice_bits() - 7; + cell cat_table = val; + ;; pfx.slice_bits() will contain 8m, where m is number of bytes in subdomain + ;; COUNTING the zero byte (if structurally correct: no multiple-ZB keys) + ;; which corresponds to 8m, m=one plus the number of bytes in the subdomain found) + if (category == 0) { + return (pfx_bits, cat_table); ;; return cell with entire dictionary for 0 + } else { + cell cat_found = cat_table.idict_get_ref(16, category); + return (pfx_bits, cat_found); + } +} diff --git a/submodules/ton/tonlib-src/crypto/smartcont/elector-code.fc b/submodules/ton/tonlib-src/crypto/smartcont/elector-code.fc index fe000c14d4..e3f394e09c 100644 --- a/submodules/ton/tonlib-src/crypto/smartcont/elector-code.fc +++ b/submodules/ton/tonlib-src/crypto/smartcont/elector-code.fc @@ -123,7 +123,7 @@ _ ~credit_to(credits, addr, amount) { } ;; parse current election data var (elect_at, elect_close, min_stake, total_stake, members, failed, finished) = elect.unpack_elect(); - elect_at~dump(); + ;; elect_at~dump(); msg_value -= 1000000000; ;; deduct GR$1 for sending confirmation if ((msg_value << 12) < total_stake) { ;; stake smaller than 1/4096 of the total accumulated stakes, return @@ -338,7 +338,7 @@ int upgrade_code(s_addr, cs, query_id) { var code = cs~load_ref(); set_code(code); ifnot(cs.slice_empty?()) { - set_c3(code); + set_c3(code.begin_parse().bless()); ;; run_method3(1666, s_addr, cs, query_id); after_code_upgrade(s_addr, cs, query_id); throw(0); @@ -443,7 +443,7 @@ _ compute_total_stake(l, n, m_stake) { if (f) { var (stake, _, pubkey) = (min(key~load_uint(128), max_stake), key~load_uint(32), key.preload_uint(256)); var (max_f, _, adnl_addr) = (cs~load_uint(32), cs~load_uint(256), cs.preload_uint(256)); - l = cons(tuple4(stake, max_f, pubkey, adnl_addr), l); + l = cons([stake, max_f, pubkey, adnl_addr], l); } } until (~ f); ;; l is the list of all stakes in decreasing order @@ -468,7 +468,7 @@ _ compute_total_stake(l, n, m_stake) { } ;; we have to select first m validators from list l l1 = touch(l); - l1~dump(); ;; DEBUG + ;; l1~dump(); ;; DEBUG repeat (m - 1) { l1 = cdr(l1); } @@ -480,7 +480,7 @@ _ compute_total_stake(l, n, m_stake) { var vset = new_dict(); var frozen = new_dict(); do { - var (stake, max_f, pubkey, adnl_addr) = l~list_next().untuple4(); + var [stake, max_f, pubkey, adnl_addr] = l~list_next(); ;; lookup source address first var (val, f) = members.udict_get?(256, pubkey); throw_unless(61, f); @@ -733,7 +733,7 @@ int announce_new_elections(ds, elect, credits) { (_, var min_stake) = config_param(17).begin_parse().load_grams(); ;; announce new elections var elect_at = t + elect_begin_before; - elect_at~dump(); + ;; elect_at~dump(); var elect_close = elect_at - elect_end_before; elect = pack_elect(elect_at, elect_close, min_stake, 0, new_dict(), false, false); set_data(begin_cell().store_dict(elect).store_dict(credits).store_slice(ds).end_cell()); @@ -786,12 +786,32 @@ _ participant_list() method_id { do { (id, var fs, var f) = members.udict_get_prev?(256, id); if (f) { - l = cons(pair(id, fs~load_grams()), l); + l = cons([id, fs~load_grams()], l); } } until (~ f); return l; } +;; returns the list of all participants of current elections with their data +_ participant_list_extended() method_id { + var elect = get_data().begin_parse().preload_dict(); + if (elect.null?()) { + return (0, 0, 0, 0, nil, 0, 0); + } + var (elect_at, elect_close, min_stake, total_stake, members, failed, finished) = elect.unpack_elect(); + var l = nil; + var id = (1 << 255) + ((1 << 255) - 1); + do { + (id, var cs, var f) = members.udict_get_prev?(256, id); + if (f) { + var (stake, time, max_factor, addr, adnl_addr) = (cs~load_grams(), cs~load_uint(32), cs~load_uint(32), cs~load_uint(256), cs~load_uint(256)); + cs.end_parse(); + l = cons([id, [stake, max_factor, addr, adnl_addr]], l); + } + } until (~ f); + return (elect_at, elect_close, min_stake, total_stake, l, failed, finished); +} + ;; computes the return stake int compute_returned_stake(int wallet_addr) method_id { var cs = get_data().begin_parse(); diff --git a/submodules/ton/tonlib-src/crypto/smartcont/gen-zerostate.fif b/submodules/ton/tonlib-src/crypto/smartcont/gen-zerostate.fif index 66d686241e..fefc7e4625 100644 --- a/submodules/ton/tonlib-src/crypto/smartcont/gen-zerostate.fif +++ b/submodules/ton/tonlib-src/crypto/smartcont/gen-zerostate.fif @@ -3,9 +3,10 @@ def? $1 { @' $1 } { "" } cond constant suffix { suffix $+ } : +suffix +256 1<<1- 15 / constant AllOnes wc_master setworkchain --17 setglobalid // negative value means a test instance of the blockchain +-239 setglobalid // negative value means a test instance of the blockchain // Initial state of Workchain 0 (Basic workchain) @@ -16,10 +17,10 @@ dup dup 31 boc+>B dup Bx. cr dup "basestate0" +suffix +".boc" tuck B>file ."(Initial basechain state saved to file " type .")" cr Bhashu dup =: basestate0_fhash -."file hash=" dup x. space 256 u>B dup B>base64url type cr +."file hash=" dup 64x. space 256 u>B dup B>base64url type cr "basestate0" +suffix +".fhash" B>file hashu dup =: basestate0_rhash -."root hash=" dup x. space 256 u>B dup B>base64url type cr +."root hash=" dup 64x. space 256 u>B dup B>base64url type cr "basestate0" +suffix +".rhash" B>file basestate0_rhash basestate0_fhash now 0 2 32 0 add-std-workchain @@ -54,10 +55,11 @@ Libs{ x{ABACABADABACABA} s>c public_lib x{1234} x{5678} |_ s>c private_lib }Libs // libraries -GR$1700000000 // balance +GR$4999990000 // balance 0 // split_depth 0 // ticktock -2 // mode: create +AllOnes 0 * // address +6 // mode: create+setaddr register_smc dup make_special dup constant smc1_addr Masterchain over @@ -82,8 +84,8 @@ Masterchain over // code // data empty_cell // libraries -GR$1000000 // initial balance (1m test Grams) -0 0 2 register_smc +GR$1000 // initial balance (1k test Grams) +0 0 AllOnes 6 * 6 register_smc dup make_special dup constant smc2_addr Masterchain over 2dup ."free test gram giver address = " .addr cr 2dup 6 .Addr cr @@ -120,13 +122,13 @@ Libs{ x{ABACABADABACABA} s>c public_lib x{1234} x{5678} |_ s>c public_lib }Libs // libraries -0x333333333 // balance +GR$666 // balance 0 // split_depth 3 // ticktock: tick 2 // mode: create register_smc dup make_special dup constant smc3_addr -."address = " x. cr +."address = " 64x. cr /* * @@ -139,7 +141,8 @@ empty_cell // libraries GR$10 // balance: 10 grams 0 // split_depth 2 // ticktock: tick -2 // mode: create +AllOnes 3 * // address: -1:333...333 +6 // mode: create + setaddr register_smc dup make_special dup constant smc4_addr dup constant elector_addr Masterchain swap @@ -155,14 +158,15 @@ Masterchain swap 0 capCreateStats config.version! // max-validators max-main-validators min-validators // 9 4 1 config.validator_num! -1000 100 5 config.validator_num! +1000 100 13 config.validator_num! // min-stake max-stake min-total-stake max-factor -GR$10000 GR$10000000 GR$1000000 sg~10 config.validator_stake_limits! +GR$10000 GR$10000000 GR$500000 sg~3 config.validator_stake_limits! // elected-for elect-start-before elect-end-before stakes-frozen-for // 400000 200000 4000 400000 config.election_params! -4000 2000 500 1000 config.election_params! // DEBUG +// 4000 2000 500 1000 config.election_params! // DEBUG +65536 32768 8192 32768 config.election_params! // TestNet DEBUG // config-addr = -1:5555...5555 -256 1<<1- 3 / constant config_addr +AllOnes 5 * constant config_addr config_addr config.config_smc! // elector-addr elector_addr config.elector_smc! @@ -172,8 +176,8 @@ elector_addr config.elector_smc! config.special! // gas_price gas_limit special_gas_limit gas_credit block_gas_limit freeze_due_limit delete_due_limit flat_gas_limit flat_gas_price -- -1000 sg* 1 *M dup 10000 10 *M GR$0.1 GR$1.0 100 100000 config.gas_prices! -10000 sg* 1 *M 10 *M 10000 10 *M GR$0.1 GR$1.0 100 1000000 config.mc_gas_prices! +1000 sg* 1 *M dup 10000 10 *M GR$0.1 GR$1.0 1000 1000000 config.gas_prices! +10000 sg* 1 *M 10 *M 10000 10 *M GR$0.1 GR$1.0 1000 10000000 config.mc_gas_prices! // lump_price bit_price cell_price ihr_factor first_frac next_frac 1000000 1000 sg* 100000 sg* 3/2 sg*/ 1/3 sg*/ 1/3 sg*/ config.fwd_prices! 10000000 10000 sg* 1000000 sg* 3/2 sg*/ 1/3 sg*/ 1/3 sg*/ config.mc_fwd_prices! @@ -211,10 +215,11 @@ now dup orig_vset_valid_for + 0 config.validators! * */ "auto/config-code.fif" include // code in separate source file - // data empty_cell // libraries GR$10 // balance @@ -232,7 +237,7 @@ Masterchain swap */ // pubkey amount `create-wallet1` or pubkey amount `create-wallet2` -PK'PuZPPXK5Rff9SvtoS7Y9lUuEixvy-J6aishYFj3Qn6P0pJMb GR$100000000 create-wallet1 +PK'PuZPPXK5Rff9SvtoS7Y9lUuEixvy-J6aishYFj3Qn6P0pJMb GR$1000000000 create-wallet1 PK'PuYiB1zAWzr4p8j6I681+sGUrRGcn6Ylf7vXl0xaUl/w6Xfg GR$1700000000 create-wallet0 /* diff --git a/submodules/ton/tonlib-src/crypto/smartcont/highload-wallet-code.fc b/submodules/ton/tonlib-src/crypto/smartcont/highload-wallet-code.fc index 70abb48e23..8420c1d827 100644 --- a/submodules/ton/tonlib-src/crypto/smartcont/highload-wallet-code.fc +++ b/submodules/ton/tonlib-src/crypto/smartcont/highload-wallet-code.fc @@ -39,3 +39,9 @@ int seqno() method_id { return get_data().begin_parse().preload_uint(32); } + +int get_public_key() method_id { + var cs = get_data().begin_parse(); + cs~load_uint(64); + return cs.preload_uint(256); +} diff --git a/submodules/ton/tonlib-src/crypto/smartcont/highload-wallet-v2-code.fc b/submodules/ton/tonlib-src/crypto/smartcont/highload-wallet-v2-code.fc index 88d7885563..7dd65f9e69 100644 --- a/submodules/ton/tonlib-src/crypto/smartcont/highload-wallet-v2-code.fc +++ b/submodules/ton/tonlib-src/crypto/smartcont/highload-wallet-v2-code.fc @@ -63,3 +63,9 @@ int processed?(int query_id) method_id { (_, var found) = old_queries.udict_get?(64, query_id); return found ? true : - (query_id <= last_cleaned); } + +int get_public_key() method_id { + var cs = get_data().begin_parse(); + cs~load_uint(32 + 64); + return cs.preload_uint(256); +} diff --git a/submodules/ton/tonlib-src/crypto/smartcont/highload-wallet-v2.fif b/submodules/ton/tonlib-src/crypto/smartcont/highload-wallet-v2.fif index b8f0be72e9..fd71f52aae 100755 --- a/submodules/ton/tonlib-src/crypto/smartcont/highload-wallet-v2.fif +++ b/submodules/ton/tonlib-src/crypto/smartcont/highload-wallet-v2.fif @@ -1,20 +1,41 @@ #!/usr/bin/fift -s "TonUtil.fif" include +"GetOpt.fif" include + +{ show-options-help 1 halt } : usage + +true =: allow-bounce +false =: force-bounce +3 =: send-mode // mode for SENDRAWMSG: +1 - sender pays fees, +2 - ignore errors +60 =: timeout // external message expires in 60 seconds + +begin-options + " [-n|-b] [-t] []" +cr +tab + +"Creates a request with up to 254 orders loaded from to high-load (sub)wallet created by new-highload-v2-wallet.fif, with private key loaded from file .pk " + +"and address from .addr, and saves it into .boc ('wallet-query.boc' by default)" +cr + +" is a text file with lines `SEND `" + disable-digit-options generic-help-setopt + "n" "--no-bounce" { false =: allow-bounce } short-long-option + "Clears bounce flag" option-help + "b" "--force-bounce" { true =: force-bounce } short-long-option + "Forces bounce flag" option-help + "t" "--timeout" { parse-int =: timeout } short-long-option-arg + "Sets expiration timeout in seconds (" timeout (.) $+ +" by default)" option-help + "m" "--mode" { parse-int =: send-mode } short-long-option-arg + "Sets transfer mode (0..255) for SENDRAWMSG (" send-mode (.) $+ +" by default)" + option-help + "h" "--help" { usage } short-long-option + "Shows a help message" option-help +parse-options -{ ."usage: " @' $0 type ." []" cr - ."Creates a request with up to 254 orders loaded from to high-load v2 (sub)wallet created by new-highload-v2-wallet.fif, with private key loaded from file .pk " - ."and address from .addr, and saves it into .boc ('wallet-query.boc' by default)" cr - ." is a text file with lines `SEND `" cr 1 halt -} : usage $# dup 3 < swap 4 > or ' usage if +4 :$1..n $1 =: file-base $2 parse-int dup 32 fits ' usage ifnot =: subwallet-id // parse subwallet-id { subwallet-id (.) $+ } : +subwallet $3 =: order-file -def? $4 { @' $4 } { "wallet-query" } cond constant savefile -3 constant send-mode // mode for SENDRAWMSG: +1 - sender pays fees, +2 - ignore errors -60 constant timeout // external message expires in 60 seconds +$4 "wallet-query" replace-if-null =: savefile file-base +subwallet +".addr" load-address 2dup 2constant wallet_addr @@ -29,7 +50,7 @@ variable order# order# 0! orders ! order# 1+! } : add-order // b body -- b' -{ tuck [-n|-b] [-t] []" +cr +tab + +"Creates a request with up to 254 orders loaded from to high-load (sub)wallet created by new-highload-wallet.fif, with private key loaded from file .pk " + +"and address from .addr, and saves it into .boc ('wallet-query.boc' by default)" +cr + +" is a text file with lines `SEND `" + disable-digit-options generic-help-setopt + "n" "--no-bounce" { false =: allow-bounce } short-long-option + "Clears bounce flag" option-help + "b" "--force-bounce" { true =: force-bounce } short-long-option + "Forces bounce flag" option-help + "t" "--timeout" { parse-int =: timeout } short-long-option-arg + "Sets expiration timeout in seconds (" timeout (.) $+ +" by default)" option-help + "m" "--mode" { parse-int =: send-mode } short-long-option-arg + "Sets transfer mode (0..255) for SENDRAWMSG (" send-mode (.) $+ +" by default)" + option-help + "h" "--help" { usage } short-long-option + "Shows a help message" option-help +parse-options -{ ."usage: " @' $0 type ." []" cr - ."Creates a request with up to 254 orders loaded from to high-load (sub)wallet created by new-highload-wallet.fif, with private key loaded from file .pk " - ."and address from .addr, and saves it into .boc ('wallet-query.boc' by default)" cr - ." is a text file with lines `SEND `" cr 1 halt -} : usage $# dup 4 < swap 5 > or ' usage if +5 :$1..n $1 =: file-base $2 parse-int dup 32 fits ' usage ifnot =: subwallet-id // parse subwallet-id { subwallet-id (.) $+ } : +subwallet $3 parse-int =: seqno $4 =: order-file -def? $5 { @' $5 } { "wallet-query" } cond constant savefile -3 constant send-mode // mode for SENDRAWMSG: +1 - sender pays fees, +2 - ignore errors -60 constant timeout // external message expires in 60 seconds +$5 "wallet-query" replace-if-null =: savefile file-base +subwallet +".addr" load-address 2dup 2constant wallet_addr @@ -30,7 +51,7 @@ variable order# order# 0! orders ! order# 1+! } : add-order // b body -- b' -{ tuck [-t] [-o] [...]" +cr +tab + +"Creates a request to managed DNS smart contract created by new-manual-dns.fif, with private key loaded from file .pk " + +"and address from -dns.addr, and saves it into ('" savefile $+ +"' by default)" + +cr +" is an operation description, one of" +cr +tab + +"add cat (smc | next | adnl | text )" +cr +tab + +"delete cat " +cr +tab + +"drop " + disable-digit-options generic-help-setopt + "t" "--timeout" { parse-int =: timeout } short-long-option-arg + "Sets expiration timeout in seconds (" timeout (.) $+ +" by default)" option-help + "o" "--output" { =: savefile } short-long-option-arg + "Sets output file for generated initialization message ('" savefile $+ +"' by default)" option-help + "h" "--help" { usage } short-long-option + "Shows a help message" option-help +parse-options + +$# 2 < ' usage if +2 :$1..n + +$1 =: file-base +$2 parse-int dup =: contract-id 32 fits ' usage ifnot +{ contract-id (.) $+ } : +contractid + +{ $* @ dup null? { second $@ ! } { drop } cond } : @skip +{ $* @ null? } : @end? +{ $* @ uncons $* ! } : @next +@next @next 2drop + +variable Actions +{ Actions @ cons Actions ! } : register-action + +{ @end? abort"subdomain name expected" @next dup $len 127 > abort"subdomain name too long" +} : parse-domain +{ @end? abort"category number expected" @next (number) 1 <> abort"category must be integer" + dup 16 fits not abort"category does not fit into 16 bit integer" + dup 0= abort"category must be non-zero" +} : parse-cat-num +{ @end? abort"`cat` expected" @next "cat" $= not abort"`cat` expected" parse-cat-num +} : parse-cat +{ @end? abort"smart contract address expected" + @next false parse-load-address drop triple +} : cl-parse-smc-addr +{ @end? abort"adnl address expected" + `adnl @next parse-adnl-addr pair +} : cl-parse-adnl-addr +{ @end? abort"subdomain record value expected" @next + dup "smc" $= { drop `smc cl-parse-smc-addr } { + dup "next" $= { drop `next cl-parse-smc-addr } { + dup "adnl" $= { drop cl-parse-adnl-addr } { + dup "text" $= { drop `text @next pair } { + "unknown record type "' swap $+ +"'" abort + } cond } cond } cond } cond +} : parse-value +{ ."Loading new code BoC from " dup type cr + file>B B>boc +} : load-new-code-from +{ @next dup "add" $= { drop `add parse-domain parse-cat parse-value 4 tuple register-action } { + dup "delete" $= { drop `delete parse-domain parse-cat triple register-action } { + dup "drop" $= { drop `drop parse-domain pair register-action } { + dup "upgrade" $= { drop `upgrade @next load-new-code-from pair register-action } { + "unknown action '" swap $+ +"'" abort + } cond } cond } cond } cond +} : parse-action +{ { @end? not } { parse-action } while } : parse-actions +parse-actions + +file-base +".pk" load-keypair nip constant wallet_pk +file-base +"-dns" +contractid +".addr" load-address +2dup 2constant smc_addr +."Managed manual DNS smart contract address = " 2dup .addr cr 6 .Addr cr + +."Actions: " Actions @ list-reverse .l cr + +// ( S -- S1 .. Sn n ) +{ 1 swap { dup "." $pos dup 0>= } { $| 1 $| nip rot 1+ swap } while drop swap +} : split-by-dots +// ( S -- s ) +{ dup $len dup 0= abort"subdomain cannot be empty" 126 > abort"subdomain too long" + dup 0 chr $pos 1+ abort"subdomain contains null characters" + split-by-dots s +// ( b V -- b' ) +{ dup first + dup `smc eq? { drop untriple 2swap drop x{9fd3} s, -rot Addr, 0 8 u, } { + dup `next eq? { drop untriple 2swap drop x{ba93} s, -rot Addr, } { + dup `adnl eq? { drop second swap x{ad01} s, swap 256 u, 0 8 u, } { + dup `text eq? { drop second swap x{1eda01} s, over $len 8 u, swap $, } { + abort"unknown value type" + } cond } cond } cond } cond +} : value, +{ subdomain>s dup sbits 3 >> + dup 63 > { drop s>c dict, } { rot swap 7 u, swap s, } cond +} : subdomain, +// ( A -- b ) +{ dup first + dup `add eq? { + drop 4 untuple -rot + b +// ( -- b ) +{ Actions @ dup null? { drop } { + uncons swap action>b { over null? not } { + b> swap uncons swap action>b rot ref, + } while nip } cond +} : serialize-actions +serialize-actions +dup brembits 888 < { b> +."Serialized actions are " hashu 32 1<<1- and + =: query_id + +dup ."signing message: " +dup ."resulting external message: " B dup Bx. cr +."Query_id is " query_id dup . ."= 0x" X. cr +."Query expires in " timeout . ."seconds" cr +savefile tuck B>file +."(Saved to file " type .")" cr diff --git a/submodules/ton/tonlib-src/crypto/smartcont/multisig-code.fc b/submodules/ton/tonlib-src/crypto/smartcont/multisig-code.fc index cbe2d30feb..36e21a7b7f 100644 --- a/submodules/ton/tonlib-src/crypto/smartcont/multisig-code.fc +++ b/submodules/ton/tonlib-src/crypto/smartcont/multisig-code.fc @@ -2,21 +2,32 @@ _ unpack_state() inline_ref { var ds = begin_parse(get_data()); - var res = (ds~load_uint(8), ds~load_uint(8), ds~load_uint(64), ds~load_dict(), ds~load_dict()); + var res = (ds~load_uint(32), ds~load_uint(8), ds~load_uint(8), ds~load_uint(64), ds~load_dict(), ds~load_dict()); ds.end_parse(); return res; } -_ pack_state(cell pending_queries, cell public_keys, int last_cleaned, int k, int n) inline_ref { +_ pack_state(cell pending_queries, cell owner_infos, int last_cleaned, int k, int n, int wallet_id) inline_ref { return begin_cell() + .store_uint(wallet_id, 32) .store_uint(n, 8) .store_uint(k, 8) .store_uint(last_cleaned, 64) - .store_dict(public_keys) + .store_dict(owner_infos) .store_dict(pending_queries) .end_cell(); } +_ pack_owner_info(int public_key, int flood) inline_ref { + return begin_cell() + .store_uint(public_key, 256) + .store_uint(flood, 8); +} + +_ unpack_owner_info(slice cs) inline_ref { + return (cs~load_uint(256), cs~load_uint(8)); +} + (int, int) check_signatures(cell public_keys, cell signatures, int hash, int cnt_bits) inline_ref { int cnt = 0; @@ -41,44 +52,60 @@ _ pack_state(cell pending_queries, cell public_keys, int last_cleaned, int k, in return (cnt, cnt_bits); } - () recv_internal(slice in_msg) impure { ;; do nothing for internal messages } -(int, int, slice) unpack_query_data(slice in_msg, int n, slice query, var found?) inline_ref { +(int, int, int, slice) unpack_query_data(slice in_msg, int n, slice query, var found?, int root_i) inline_ref { if (found?) { throw_unless(35, query~load_int(1)); - (int cnt, int cnt_bits, slice msg) = (query~load_uint(8), query~load_uint(n), query); + (int creator_i, int cnt, int cnt_bits, slice msg) = (query~load_uint(8), query~load_uint(8), query~load_uint(n), query); throw_unless(36, slice_hash(msg) == slice_hash(in_msg)); - return (cnt, cnt_bits, msg); + return (creator_i, cnt, cnt_bits, msg); } - return (0, 0, in_msg); + return (root_i, 0, 0, in_msg); } () try_init() impure inline_ref { ;; first query without signatures is always accepted - (int n, int k, int last_cleaned, cell public_keys, cell pending_queries) = unpack_state(); + (int wallet_id, int n, int k, int last_cleaned, cell owner_infos, cell pending_queries) = unpack_state(); throw_if(37, last_cleaned); accept_message(); - set_data(pack_state(pending_queries, public_keys, 1, k, n)); + set_data(pack_state(pending_queries, owner_infos, 1, k, n, wallet_id)); } -cell update_pending_queries(cell pending_queries, slice msg, int query_id, int cnt, int cnt_bits, int n, int k) impure inline_ref { +(cell, cell) update_pending_queries(cell pending_queries, cell owner_infos, slice msg, int query_id, int creator_i, int cnt, int cnt_bits, int n, int k) impure inline_ref { if (cnt >= k) { + accept_message(); while (msg.slice_refs()) { var mode = msg~load_uint(8); send_raw_message(msg~load_ref(), mode); } pending_queries~udict_set_builder(64, query_id, begin_cell().store_int(0, 1)); + + (slice owner_info, var found?) = owner_infos.udict_get?(8, creator_i); + (int public_key, int flood) = unpack_owner_info(owner_info); + owner_infos~udict_set_builder(8, creator_i, pack_owner_info(public_key, flood - 1)); } else { pending_queries~udict_set_builder(64, query_id, begin_cell() .store_uint(1, 1) + .store_uint(creator_i, 8) .store_uint(cnt, 8) .store_uint(cnt_bits, n) .store_slice(msg)); } - return pending_queries; + return (pending_queries, owner_infos); +} + +(int, int) calc_boc_size(int cells, int bits, slice root) { + cells += 1; + bits += root.slice_bits(); + + while (root.slice_refs()) { + (cells, bits) = calc_boc_size(cells, bits, root~load_ref().begin_parse()); + } + + return (cells, bits); } () recv_external(slice in_msg) impure { @@ -92,44 +119,62 @@ cell update_pending_queries(cell pending_queries, slice msg, int query_id, int c int root_hash = slice_hash(in_msg); int root_i = in_msg~load_uint(8); - (int n, int k, int last_cleaned, cell public_keys, cell pending_queries) = unpack_state(); + (int wallet_id, int n, int k, int last_cleaned, cell owner_infos, cell pending_queries) = unpack_state(); last_cleaned -= last_cleaned == 0; - (slice public_key, var found?) = public_keys.udict_get?(8, root_i); + (slice owner_info, var found?) = owner_infos.udict_get?(8, root_i); + (int public_key, int flood) = unpack_owner_info(owner_info); throw_unless(31, found?); - throw_unless(32, check_signature(root_hash, root_signature, public_key.preload_uint(256))); + throw_unless(32, check_signature(root_hash, root_signature, public_key)); cell signatures = in_msg~load_dict(); var hash = slice_hash(in_msg); + int query_wallet_id = in_msg~load_uint(32); + throw_unless(42, query_wallet_id == wallet_id); + int query_id = in_msg~load_uint(64); + (int cnt, int bits) = calc_boc_size(0, 0, in_msg); + throw_if(40, (cnt > 8) | (bits > 2048)); + + (slice query, var found?) = pending_queries.udict_get?(64, query_id); + + ifnot (found?) { + flood += 1; + throw_if(39, flood > 10); + } + var bound = (now() << 32); throw_if(33, query_id < bound); - (slice query, var found?) = pending_queries.udict_get?(64, query_id); - (int cnt, int cnt_bits, slice msg) = unpack_query_data(in_msg, n, query, found?); + (int creator_i, int cnt, int cnt_bits, slice msg) = unpack_query_data(in_msg, n, query, found?, root_i); int mask = 1 << root_i; throw_if(34, cnt_bits & mask); cnt_bits |= mask; cnt += 1; - ;; TODO: reserve some gas or FAIL - accept_message(); + set_gas_limit(100000); - pending_queries = update_pending_queries(pending_queries, msg, query_id, cnt, cnt_bits, n, k); - set_data(pack_state(pending_queries, public_keys, last_cleaned, k, n)); + ifnot (found?) { + owner_infos~udict_set_builder(8, root_i, pack_owner_info(public_key, flood)); + throw_if(41, (cnt < k) & (bound + ((60 * 60) << 32) > query_id)); + } + + (pending_queries, owner_infos) = update_pending_queries(pending_queries, owner_infos, msg, query_id, creator_i, cnt, cnt_bits, n, k); + set_data(pack_state(pending_queries, owner_infos, last_cleaned, k, n, wallet_id)); commit(); int need_save = 0; ifnot (cell_null?(signatures) | (cnt >= k)) { - (int new_cnt, cnt_bits) = check_signatures(public_keys, signatures, hash, cnt_bits); + (int new_cnt, cnt_bits) = check_signatures(owner_infos, signatures, hash, cnt_bits); cnt += new_cnt; - pending_queries = update_pending_queries(pending_queries, msg, query_id, cnt, cnt_bits, n, k); + (pending_queries, owner_infos) = update_pending_queries(pending_queries, owner_infos, msg, query_id, creator_i, cnt, cnt_bits, n, k); need_save = -1; } + accept_message(); bound -= (64 << 32); ;; clean up records expired more than 64 seconds ago int old_last_cleaned = last_cleaned; do { @@ -146,18 +191,18 @@ cell update_pending_queries(cell pending_queries, slice msg, int query_id, int c } until (~ f); if (need_save) { - set_data(pack_state(pending_queries, public_keys, last_cleaned, k, n)); + set_data(pack_state(pending_queries, owner_infos, last_cleaned, k, n, wallet_id)); } } ;; Get methods ;; returns -1 for processed queries, 0 for unprocessed, 1 for unknown (forgotten) (int, int) get_query_state(int query_id) method_id { - (int n, _, int last_cleaned, _, cell pending_queries) = unpack_state(); + (_, int n, _, int last_cleaned, _, cell pending_queries) = unpack_state(); (slice cs, var found) = pending_queries.udict_get?(64, query_id); if (found) { if (cs~load_int(1)) { - cs~load_uint(8); + cs~load_uint(8 + 8); return (0, cs~load_uint(n)); } else { return (-1, 0); @@ -172,8 +217,8 @@ int processed?(int query_id) method_id { return x; } -cell create_init_state(int n, int k, cell public_keys) method_id { - return pack_state(new_dict(), public_keys, 0, k, n); +cell create_init_state(int wallet_id, int n, int k, cell owners_info) method_id { + return pack_state(new_dict(), owners_info, 0, k, n, wallet_id); } cell merge_list(cell a, cell b) { @@ -196,7 +241,7 @@ cell merge_list(cell a, cell b) { } cell get_public_keys() method_id { - (_, _, _, cell public_keys, _) = unpack_state(); + (_, _, _, _, cell public_keys, _) = unpack_state(); return public_keys; } @@ -222,14 +267,14 @@ cell get_public_keys() method_id { } cell messages_by_mask(int mask) method_id { - (int n, _, _, _, cell pending_queries) = unpack_state(); + (_, int n, _, _, _, cell pending_queries) = unpack_state(); int i = -1; cell a = new_dict(); do { (i, var cs, var f) = pending_queries.udict_get_next?(64, i); if (f) { if (cs~load_int(1)) { - int cnt_bits = cs.skip_bits(8).preload_uint(n); + int cnt_bits = cs.skip_bits(8 + 8).preload_uint(n); if (cnt_bits & mask) { a~udict_set_builder(64, i, begin_cell().store_slice(cs)); } @@ -248,7 +293,7 @@ cell get_messages_unsigned() method_id { } (int, int) get_n_k() method_id { - (int n, int k, _, _, _) = unpack_state(); + (_, int n, int k, _, _, _) = unpack_state(); return (n, k); } diff --git a/submodules/ton/tonlib-src/crypto/smartcont/new-auto-dns.fif b/submodules/ton/tonlib-src/crypto/smartcont/new-auto-dns.fif new file mode 100644 index 0000000000..3d4848b4d7 --- /dev/null +++ b/submodules/ton/tonlib-src/crypto/smartcont/new-auto-dns.fif @@ -0,0 +1,66 @@ +#!/usr/bin/fift -s +"TonUtil.fif" include +"Asm.fif" include +"GetOpt.fif" include + +{ show-options-help 1 halt } : usage + +Basechain =: wc // create smart contract in basechain +"new-dns-query.boc" =: savefile +0 =: contract-id +variable dns-dict dictnew dns-dict ! + +begin-options + "

    [-w] [-r] [-o]" +cr +tab + +"Creates a new automatic dns smart contract with 32-bit identifier controlled from wallet with address
    " + +"and saves it into ('" savefile $+ +"' by default)" + disable-digit-options generic-help-setopt + "w" "--workchain" { parse-workchain-id =: wc } short-long-option-arg + "Selects workchain to create smart contract (" wc (.) $+ +" by default)" option-help + "r" "--random-id" { parse-int =: contract-id } short-long-option-arg + "Sets 'random' smart contract identifier (" contract-id (.) $+ +" by default)" option-help + "o" "--output" { =: savefile } short-long-option-arg + "Sets output file for generated initialization message ('" savefile $+ +"' by default)" option-help + "h" "--help" { usage } short-long-option + "Shows a help message" option-help +parse-options + +$# 6 <> ' usage if +6 :$1..n +$1 =: file-base +$2 false parse-load-address drop 2=: ctl-addr +$3 parse-int dup 0 10000000 in-range? ' usage ifnot =: reg-period +$4 $>GR =: reg-price +$5 parse-int dup 0< ' usage if =: ng-pb +$6 parse-int dup 0< ' usage if =: ng-pc +contract-id 32 fits ' usage ifnot +{ contract-id ?dup { (.) $+ } if } : +contractid + +."Creating new automatic DNS smart contract in workchain " wc . +."with random id " contract-id . cr +."Controlling wallet (smart contract) is " ctl-addr 6 .Addr cr +."Subdomain registration period is " reg-period . ."seconds" cr +."Subdomain registration price is " reg-price .GR +."+ " ng-pc . ."per cell + " ng-pb . ."per bit" cr + +// Create new automatic DNS; source code included from `auto/dns-auto-code.fif` +"auto/dns-auto-code.fif" include +// code + ref, // ctl + dns-dict @ dict, dictnew dict, // dom_dict gc + reg-period 30 u, reg-price Gram, ng-pc Gram, ng-pb Gram, // stdper ppc ppb + 0 64 u, // nhk lhk +b> // data +null // no libraries + // create StateInit +dup ."StateInit: " +dup ."External message for initialization is " B dup Bx. cr +savefile tuck B>file +."(Saved dns smart-contract creating query to file " type .")" cr diff --git a/submodules/ton/tonlib-src/crypto/smartcont/new-manual-dns.fif b/submodules/ton/tonlib-src/crypto/smartcont/new-manual-dns.fif new file mode 100644 index 0000000000..47b57bbee3 --- /dev/null +++ b/submodules/ton/tonlib-src/crypto/smartcont/new-manual-dns.fif @@ -0,0 +1,63 @@ +#!/usr/bin/fift -s +"TonUtil.fif" include +"Asm.fif" include +"GetOpt.fif" include + +{ show-options-help 1 halt } : usage + +Basechain =: wc // create smart contract in basechain +65536 =: timeout +"new-dns-query.boc" =: savefile +variable dns-dict dictnew dns-dict ! + +begin-options + " [-w] [-t] [-o]" +cr +tab + +"Creates a new manual dns smart contract with 32-bit identifier managed by private key .pk, " + +"and saves it into ('" savefile $+ +"' by default)" + disable-digit-options generic-help-setopt + "w" "--workchain" { parse-workchain-id =: wc } short-long-option-arg + "Selects workchain to create smart contract (" wc (.) $+ +" by default)" option-help + "t" "--timeout" { parse-int =: timeout } short-long-option-arg + "Sets expiration timeout for the initialization message in seconds (" timeout (.) $+ +" by default)" option-help + "o" "--output" { =: savefile } short-long-option-arg + "Sets output file for generated initialization message ('" savefile $+ +"' by default)" option-help + "h" "--help" { usage } short-long-option + "Shows a help message" option-help +parse-options + +$# 2 <> ' usage if +2 :$1..n +$1 =: file-base +$2 parse-int dup =: contract-id +32 fits ' usage ifnot +{ contract-id (.) $+ } : +contractid + +."Creating new manual DNS smart contract in workchain " wc . +."with contract id " contract-id . cr + +// Create new manual DNS; source code included from `auto/dns-manual-code.fif` +"auto/dns-manual-code.fif" include +// code + // data +null // no libraries + // create StateInit +dup ."StateInit: " +dup ."signing message: " +dup ."External message for initialization is " B dup Bx. cr +savefile tuck B>file +."(Saved dns smart-contract creating query to file " type .")" cr diff --git a/submodules/ton/tonlib-src/crypto/smartcont/new-wallet-v2.fif b/submodules/ton/tonlib-src/crypto/smartcont/new-wallet-v2.fif index d59c6c5201..0bb2bcd19c 100755 --- a/submodules/ton/tonlib-src/crypto/smartcont/new-wallet-v2.fif +++ b/submodules/ton/tonlib-src/crypto/smartcont/new-wallet-v2.fif @@ -15,8 +15,8 @@ def? $2 { @' $2 } { "new-wallet" } cond constant file-base // Create new advanced wallet; code adapted from `auto/wallet-code.fif` <{ SETCP0 DUP IFNOTRET // return if recv_internal - DUP 85143 INT EQUAL IFJMP:<{ // "seqno" get-method - DROP c4 PUSHCTR CTOS 32 PLDU // cnt + DUP 85143 INT EQUAL OVER 78748 INT EQUAL OR IFJMP:<{ // "seqno" and "get_public_key" get-methods + 1 INT AND c4 PUSHCTR CTOS 32 LDU 256 PLDU CONDSEL // cnt or pubk }> INC 32 THROWIF // fail unless recv_external 9 PUSHPOW2 LDSLICEX DUP 32 LDU 32 LDU // signature in_msg msg_seqno valid_until cs diff --git a/submodules/ton/tonlib-src/crypto/smartcont/new-wallet-v3.fif b/submodules/ton/tonlib-src/crypto/smartcont/new-wallet-v3.fif index 187519c9cd..61e392a0e1 100644 --- a/submodules/ton/tonlib-src/crypto/smartcont/new-wallet-v3.fif +++ b/submodules/ton/tonlib-src/crypto/smartcont/new-wallet-v3.fif @@ -2,23 +2,24 @@ "TonUtil.fif" include "Asm.fif" include -{ ."usage: " @' $0 type ." []" cr +{ ."usage: " $0 type ." []" cr ."Creates a new advanced wallet with unique 32-bit identifier in specified workchain, with private key saved to or loaded from .pk" cr ."('new-wallet.pk' by default)" cr 1 halt } : usage $# 2- -2 and ' usage if +3 :$1..n $1 parse-workchain-id =: wc // set workchain id from command line argument $2 parse-int =: subwallet-id -def? $3 { @' $3 } { "new-wallet" } cond constant file-base +$3 "new-wallet" replace-if-null =: file-base ."Creating new advanced v3 wallet in workchain " wc . cr ."with unique wallet id " subwallet-id . cr // Create new advanced wallet; code adapted from `auto/wallet3-code.fif` <{ SETCP0 DUP IFNOTRET // return if recv_internal - DUP 85143 INT EQUAL IFJMP:<{ // "seqno" get-method - DROP c4 PUSHCTR CTOS 32 PLDU // cnt + DUP 85143 INT EQUAL OVER 78748 INT EQUAL OR IFJMP:<{ // "seqno" and "get_public_key" get-methods + 1 INT AND c4 PUSHCTR CTOS 32 LDU 32 LDU NIP 256 PLDU CONDSEL // cnt or pubk }> INC 32 THROWIF // fail unless recv_external 9 PUSHPOW2 LDSLICEX DUP 32 LDU 32 LDU 32 LDU // signature in_msg subwallet_id valid_until msg_seqno cs diff --git a/submodules/ton/tonlib-src/crypto/smartcont/new-wallet.fif b/submodules/ton/tonlib-src/crypto/smartcont/new-wallet.fif index ac8d4a0e3a..b1aead9000 100755 --- a/submodules/ton/tonlib-src/crypto/smartcont/new-wallet.fif +++ b/submodules/ton/tonlib-src/crypto/smartcont/new-wallet.fif @@ -15,8 +15,8 @@ def? $2 { @' $2 } { "new-wallet" } cond constant file-base // Create new simple wallet <{ SETCP0 DUP IFNOTRET // return if recv_internal - DUP 85143 INT EQUAL IFJMP:<{ // "seqno" get-method - DROP c4 PUSHCTR CTOS 32 PLDU // cnt + DUP 85143 INT EQUAL OVER 78748 INT EQUAL OR IFJMP:<{ // "seqno" and "get_public_key" get-methods + 1 INT AND c4 PUSHCTR CTOS 32 LDU 256 PLDU CONDSEL // cnt or pubk }> INC 32 THROWIF // fail unless recv_external 512 INT LDSLICEX DUP 32 PLDU // sign cs cnt diff --git a/submodules/ton/tonlib-src/crypto/smartcont/restricted-wallet-code.fc b/submodules/ton/tonlib-src/crypto/smartcont/restricted-wallet-code.fc index 83639dfdff..a31683406f 100644 --- a/submodules/ton/tonlib-src/crypto/smartcont/restricted-wallet-code.fc +++ b/submodules/ton/tonlib-src/crypto/smartcont/restricted-wallet-code.fc @@ -62,6 +62,12 @@ int seqno() method_id { return get_data().begin_parse().preload_uint(32); } -int balance() method_id { - return restricted?() ? 0 : get_balance().first(); +int get_public_key() method_id { + var cs = get_data().begin_parse(); + cs~load_uint(32); + return cs.preload_uint(256); +} + +int balance() method_id { + return restricted?() ? 0 : get_balance().pair_first(); } diff --git a/submodules/ton/tonlib-src/crypto/smartcont/restricted-wallet2-code.fc b/submodules/ton/tonlib-src/crypto/smartcont/restricted-wallet2-code.fc index fa57e77d24..8d509886e1 100644 --- a/submodules/ton/tonlib-src/crypto/smartcont/restricted-wallet2-code.fc +++ b/submodules/ton/tonlib-src/crypto/smartcont/restricted-wallet2-code.fc @@ -55,12 +55,18 @@ int seqno() method_id { return get_data().begin_parse().preload_uint(32); } +int get_public_key() method_id { + var cs = get_data().begin_parse(); + cs~load_uint(32); + return cs.preload_uint(256); +} + int balance() method_id { var ds = get_data().begin_parse().skip_bits(32 + 256); var rdict = ds~load_dict(); ds.end_parse(); var ts = days_passed(); - var balance = get_balance().first(); + var balance = get_balance().pair_first(); var (_, value, found) = rdict.idict_get_preveq?(16, ts); if (found) { balance = max(balance - value~load_grams(), 0); diff --git a/submodules/ton/tonlib-src/crypto/smartcont/show-addr.fif b/submodules/ton/tonlib-src/crypto/smartcont/show-addr.fif index 5d3094644f..86b314630b 100755 --- a/submodules/ton/tonlib-src/crypto/smartcont/show-addr.fif +++ b/submodules/ton/tonlib-src/crypto/smartcont/show-addr.fif @@ -1,19 +1,20 @@ #!/usr/bin/fift -s "TonUtil.fif" include -{ ."usage: " @' $0 type ." " cr +{ ."usage: " $0 type ." " cr ."Shows the address of a simple wallet created by new-wallet.fif, with address in .addr " ."and private key in file .pk" cr 1 halt } : usage -def? $# { @' $# 1 > ' usage if } if -def? $1 { @' $1 } { "new-wallet" } cond constant file-base +$# 1 > ' usage if +1 :$1..n +$1 "new-wallet" replace-if-null =: file-base file-base +".addr" dup ."Loading wallet address from " type cr file>B 32 B| dup Blen { 32 B>i@ } { drop Basechain } cond constant wallet_wc 256 B>u@ dup constant wallet_addr -."Source wallet address = " wallet_wc ._ .":" x. cr -wallet_wc wallet_addr 2dup 7 smca>$ ."Non-bounceable address (for init only): " type cr -6 smca>$ ."Bounceable address (for later access): " type cr +."Source wallet address = " wallet_wc swap 2dup .addr cr +."Non-bounceable address (for init only): " 2dup 7 .Addr cr +."Bounceable address (for later access): " 6 .Addr cr file-base +".pk" dup file-exists? { dup file>B dup Blen 32 <> abort"Private key must be exactly 32 bytes long" diff --git a/submodules/ton/tonlib-src/crypto/smartcont/simple-wallet-code.fc b/submodules/ton/tonlib-src/crypto/smartcont/simple-wallet-code.fc index 266bc9ac1f..a43b8b9299 100644 --- a/submodules/ton/tonlib-src/crypto/smartcont/simple-wallet-code.fc +++ b/submodules/ton/tonlib-src/crypto/smartcont/simple-wallet-code.fc @@ -15,7 +15,7 @@ throw_unless(33, msg_seqno == stored_seqno); throw_unless(34, check_signature(slice_hash(in_msg), signature, public_key)); accept_message(); - cs~touch_slice(); + cs~touch(); if (cs.slice_refs()) { var mode = cs~load_uint(8); send_raw_message(cs~load_ref(), mode); diff --git a/submodules/ton/tonlib-src/crypto/smartcont/simple-wallet-ext-code.fc b/submodules/ton/tonlib-src/crypto/smartcont/simple-wallet-ext-code.fc index a20b96a861..fb43e83325 100644 --- a/submodules/ton/tonlib-src/crypto/smartcont/simple-wallet-ext-code.fc +++ b/submodules/ton/tonlib-src/crypto/smartcont/simple-wallet-ext-code.fc @@ -30,7 +30,7 @@ slice do_verify_message(slice in_msg, int seqno, int public_key) { (int stored_seqno, int public_key) = load_state(); var cs = do_verify_message(in_msg, stored_seqno, public_key); accept_message(); - cs~touch_slice(); + cs~touch(); if (cs.slice_refs()) { var mode = cs~load_uint(8); send_raw_message(cs~load_ref(), mode); @@ -45,6 +45,11 @@ int seqno() method_id { return get_data().begin_parse().preload_uint(32); } +int get_public_key() method_id { + var (seqno, public_key) = load_state(); + return public_key; +} + cell create_init_state(int public_key) method_id { return create_state(0, public_key); } @@ -57,11 +62,7 @@ cell prepare_send_message(int mode, cell msg) method_id { return prepare_send_message_with_seqno(mode, msg, seqno()); } - slice verify_message(slice msg) method_id { var (stored_seqno, public_key) = load_state(); return do_verify_message(msg, stored_seqno, public_key); } - - - diff --git a/submodules/ton/tonlib-src/crypto/smartcont/stdlib.fc b/submodules/ton/tonlib-src/crypto/smartcont/stdlib.fc index 0798a0a1b5..ca8337e133 100644 --- a/submodules/ton/tonlib-src/crypto/smartcont/stdlib.fc +++ b/submodules/ton/tonlib-src/crypto/smartcont/stdlib.fc @@ -6,21 +6,34 @@ forall X -> (X, tuple) uncons(tuple list) asm "UNCONS"; forall X -> (tuple, X) list_next(tuple list) asm( -> 1 0) "UNCONS"; forall X -> X car(tuple list) asm "CAR"; tuple cdr(tuple list) asm "CDR"; -forall X, Y -> tuple pair(X x, Y y) asm "PAIR"; -forall X, Y -> (X, Y) unpair(tuple t) asm "UNPAIR"; -forall X, Y, Z -> tuple triple(X x, Y y, Z z) asm "TRIPLE"; -forall X, Y, Z -> (X, Y, Z) untriple(tuple t) asm "UNTRIPLE"; -forall X, Y, Z, W -> tuple tuple4(X x, Y y, Z z, W w) asm "4 TUPLE"; -forall X, Y, Z, W -> (X, Y, Z, W) untuple4(tuple t) asm "4 UNTUPLE"; +tuple empty_tuple() asm "NIL"; +forall X -> tuple tpush(tuple t, X value) asm "TPUSH"; +forall X -> (tuple, ()) ~tpush(tuple t, X value) asm "TPUSH"; +forall X -> [X] single(X x) asm "SINGLE"; +forall X -> X unsingle([X] t) asm "UNSINGLE"; +forall X, Y -> [X, Y] pair(X x, Y y) asm "PAIR"; +forall X, Y -> (X, Y) unpair([X, Y] t) asm "UNPAIR"; +forall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) asm "TRIPLE"; +forall X, Y, Z -> (X, Y, Z) untriple([X, Y, Z] t) asm "UNTRIPLE"; +forall X, Y, Z, W -> [X, Y, Z, W] tuple4(X x, Y y, Z z, W w) asm "4 TUPLE"; +forall X, Y, Z, W -> (X, Y, Z, W) untuple4([X, Y, Z, W] t) asm "4 UNTUPLE"; forall X -> X first(tuple t) asm "FIRST"; forall X -> X second(tuple t) asm "SECOND"; forall X -> X third(tuple t) asm "THIRD"; forall X -> X fourth(tuple t) asm "3 INDEX"; +forall X, Y -> X pair_first([X, Y] p) asm "FIRST"; +forall X, Y -> Y pair_second([X, Y] p) asm "SECOND"; +forall X, Y, Z -> X triple_first([X, Y, Z] p) asm "FIRST"; +forall X, Y, Z -> Y triple_second([X, Y, Z] p) asm "SECOND"; +forall X, Y, Z -> Z triple_third([X, Y, Z] p) asm "THIRD"; forall X -> X null() asm "PUSHNULL"; +forall X -> (X, ()) ~impure_touch(X x) impure asm "NOP"; int now() asm "NOW"; slice my_address() asm "MYADDR"; -tuple get_balance() asm "BALANCE"; +[int, cell] get_balance() asm "BALANCE"; +int cur_lt() asm "LTIME"; +int block_lt() asm "BLOCKLT"; int cell_hash(cell c) asm "HASHCU"; int slice_hash(slice s) asm "HASHSU"; @@ -29,16 +42,23 @@ int string_hash(slice s) asm "SHA256U"; int check_signature(int hash, slice signature, int public_key) asm "CHKSIGNU"; int check_data_signature(slice data, slice signature, int public_key) asm "CHKSIGNS"; +(int, int, int) compute_data_size(cell c, int max_cells) asm "CDATASIZE"; +(int, int, int) slice_compute_data_size(slice s, int max_cells) asm "SDATASIZE"; + ;; () throw_if(int excno, int cond) impure asm "THROWARGIF"; () dump_stack() impure asm "DUMPSTK"; cell get_data() asm "c4 PUSH"; () set_data(cell c) impure asm "c4 POP"; -cell get_c3() impure asm "c3 PUSH"; -() set_c3(cell c) impure asm "c3 POP"; +cont get_c3() impure asm "c3 PUSH"; +() set_c3(cont c) impure asm "c3 POP"; +cont bless(slice s) impure asm "BLESS"; + () accept_message() impure asm "ACCEPT"; +() set_gas_limit(int limit) impure asm "SETGASLIMIT"; () commit() impure asm "COMMIT"; +() buy_gas(int gram) impure asm "BUYGAS"; int min(int x, int y) asm "MIN"; int max(int x, int y) asm "MAX"; @@ -59,16 +79,28 @@ slice skip_bits(slice s, int len) asm "SDSKIPFIRST"; slice first_bits(slice s, int len) asm "SDCUTFIRST"; slice skip_last_bits(slice s, int len) asm "SDSKIPLAST"; (slice, ()) ~skip_last_bits(slice s, int len) asm "SDSKIPLAST"; +slice slice_last(slice s, int len) asm "SDCUTLAST"; (slice, cell) load_dict(slice s) asm( -> 1 0) "LDDICT"; cell preload_dict(slice s) asm "PLDDICT"; slice skip_dict(slice s) asm "SKIPDICT"; +(slice, cell) load_maybe_ref(slice s) asm( -> 1 0) "LDOPTREF"; +cell preload_maybe_ref(slice s) asm "PLDOPTREF"; +builder store_maybe_ref(builder b, cell c) asm(c b) "STOPTREF"; + +int cell_depth(cell c) asm "CDEPTH"; + int slice_refs(slice s) asm "SREFS"; int slice_bits(slice s) asm "SBITS"; (int, int) slice_bits_refs(slice s) asm "SBITREFS"; int slice_empty?(slice s) asm "SEMPTY"; int slice_data_empty?(slice s) asm "SDEMPTY"; int slice_refs_empty?(slice s) asm "SREMPTY"; +int slice_depth(slice s) asm "SDEPTH"; + +int builder_refs(builder b) asm "BREFS"; +int builder_bits(builder b) asm "BBITS"; +int builder_depth(builder b) asm "BDEPTH"; builder begin_cell() asm "NEWC"; cell end_cell(builder b) asm "ENDC"; @@ -89,7 +121,8 @@ cell idict_set_ref(cell dict, int key_len, int index, cell value) asm(value inde cell udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF"; (cell, ()) ~udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF"; cell idict_get_ref(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETOPTREF"; -cell udict_get_ref(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGETOPTREF"; +(cell, int) idict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETREF"; +(cell, int) udict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGETREF"; (cell, cell) idict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETGETOPTREF"; (cell, cell) udict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETGETOPTREF"; (cell, int) idict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDEL"; @@ -120,36 +153,52 @@ cell dict_set_builder(cell dict, int key_len, slice index, builder value) asm(va (cell, int) udict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUREPLACEB"; (cell, int) idict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIADDB"; (cell, int) idict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIREPLACEB"; -(cell, int, slice, int) udict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT" "NULLSWAPIFNOT"; -(cell, (int, slice, int)) ~udict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT" "NULLSWAPIFNOT"; -(cell, int, slice, int) idict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT" "NULLSWAPIFNOT"; -(cell, (int, slice, int)) ~idict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT" "NULLSWAPIFNOT"; -(cell, slice, slice, int) dict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT" "NULLSWAPIFNOT"; -(cell, (slice, slice, int)) ~dict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT" "NULLSWAPIFNOT"; -(cell, int, slice, int) udict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT" "NULLSWAPIFNOT"; -(cell, (int, slice, int)) ~udict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT" "NULLSWAPIFNOT"; -(cell, int, slice, int) idict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT" "NULLSWAPIFNOT"; -(cell, (int, slice, int)) ~idict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT" "NULLSWAPIFNOT"; -(cell, slice, slice, int) dict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT" "NULLSWAPIFNOT"; -(cell, (slice, slice, int)) ~dict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT" "NULLSWAPIFNOT"; -(int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT" "NULLSWAPIFNOT"; -(int, slice, int) udict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXTEQ" "NULLSWAPIFNOT" "NULLSWAPIFNOT"; -(int, slice, int) udict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT" "NULLSWAPIFNOT"; -(int, slice, int) udict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREVEQ" "NULLSWAPIFNOT" "NULLSWAPIFNOT"; -(int, slice, int) idict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT" "NULLSWAPIFNOT"; -(int, slice, int) idict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXTEQ" "NULLSWAPIFNOT" "NULLSWAPIFNOT"; -(int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT" "NULLSWAPIFNOT"; -(int, slice, int) idict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT" "NULLSWAPIFNOT"; +(cell, int, slice, int) udict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~udict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; +(cell, int, slice, int) idict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~idict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; +(cell, slice, slice, int) dict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; +(cell, (slice, slice, int)) ~dict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; +(cell, int, slice, int) udict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~udict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; +(cell, int, slice, int) idict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~idict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; +(cell, slice, slice, int) dict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; +(cell, (slice, slice, int)) ~dict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMIN" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAX" "NULLSWAPIFNOT2"; +(int, cell, int) udict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMINREF" "NULLSWAPIFNOT2"; +(int, cell, int) udict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAXREF" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAX" "NULLSWAPIFNOT2"; +(int, cell, int) idict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMINREF" "NULLSWAPIFNOT2"; +(int, cell, int) idict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAXREF" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXTEQ" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREVEQ" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXTEQ" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT2"; cell new_dict() asm "NEWDICT"; int dict_empty?(cell c) asm "DICTEMPTY"; +(slice, slice, slice, int) pfxdict_get?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTGETQ" "NULLSWAPIFNOT2"; +(cell, int) pfxdict_set?(cell dict, int key_len, slice key, slice value) asm(value key dict key_len) "PFXDICTSET"; +(cell, int) pfxdict_delete?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTDEL"; + cell config_param(int x) asm "CONFIGOPTPARAM"; int cell_null?(cell c) asm "ISNULL"; () raw_reserve(int amount, int mode) impure asm "RAWRESERVE"; -() raw_reserve_extra(slice currencies, int mode) impure asm "RAWRESERVEX"; +() raw_reserve_extra(int amount, cell extra_amount, int mode) impure asm "RAWRESERVEX"; () send_raw_message(cell msg, int mode) impure asm "SENDRAWMSG"; () set_code(cell new_code) impure asm "SETCODE"; -slice touch_slice(slice s) asm "NOP"; -(slice,()) ~touch_slice(slice s) asm "NOP"; +int random() impure asm "RANDU256"; +int rand(int range) impure asm "RAND"; +int get_seed() impure asm "RANDSEED"; +int set_seed() impure asm "SETRAND"; +() randomize(int x) impure asm "ADDRAND"; +() randomize_lt() impure asm "LTIME" "ADDRAND"; diff --git a/submodules/ton/tonlib-src/crypto/smartcont/update-config-smc.fif b/submodules/ton/tonlib-src/crypto/smartcont/update-config-smc.fif index 33e5fbcebc..3924363223 100755 --- a/submodules/ton/tonlib-src/crypto/smartcont/update-config-smc.fif +++ b/submodules/ton/tonlib-src/crypto/smartcont/update-config-smc.fif @@ -1,7 +1,7 @@ #!/usr/bin/fift -s "TonUtil.fif" include -{ ."usage: " @' $0 type ." []" cr +{ ."usage: " $0 type ." []" cr ."Creates a request to simple configuration smart contract requesting to change configuration smart contract code to the one currently stored in auto/config-code.fif, " ."with private key loaded from file .pk, " ."and saves it into .boc ('config-query.boc' by default)" cr 1 halt @@ -9,15 +9,16 @@ $# dup 2 < swap 3 > or ' usage if "config-master" constant file-base -0 constant seqno +0 constant qseqno -1 constant idx true constant bounce "auto/config-code.fif" constant config-source 100 constant interval // valid for 100 seconds +3 :$1..n $1 =: file-base -$2 parse-int =: seqno -def? $3 { @' $3 } { "config-query" } cond constant savefile +$2 parse-int =: qseqno +$3 "config-query" replace-if-null constant savefile file-base +".addr" load-address 2dup 2constant config_addr @@ -30,7 +31,7 @@ config-source include dup + dup ."signing message: " B B+ max_factor 32 u>B B+ src_addr 256 u>B B+ adnl_addr 256 u>B B+ dup Bx. cr diff --git a/submodules/ton/tonlib-src/crypto/smartcont/validator-elect-signed.fif b/submodules/ton/tonlib-src/crypto/smartcont/validator-elect-signed.fif index 55e3d9ddac..4e681f07dc 100755 --- a/submodules/ton/tonlib-src/crypto/smartcont/validator-elect-signed.fif +++ b/submodules/ton/tonlib-src/crypto/smartcont/validator-elect-signed.fif @@ -27,7 +27,7 @@ def? $7 { @' $7 } { "validator-query.boc" } cond constant output_fname ."Creating a request to participate in validator elections at time " elect_time . ."from smart contract " -1 src_addr 2dup 1 .Addr ." = " .addr ." with maximal stake factor with respect to the minimal stake " max_factor ._ -."/65536 and validator ADNL address " adnl_addr x. cr +."/65536 and validator ADNL address " adnl_addr 64x. cr B{654c5074} elect_time 32 u>B B+ max_factor 32 u>B B+ src_addr 256 u>B B+ adnl_addr 256 u>B B+ ."String to sign is: " dup Bx. cr constant to_sign diff --git a/submodules/ton/tonlib-src/crypto/smartcont/wallet-code.fc b/submodules/ton/tonlib-src/crypto/smartcont/wallet-code.fc index 3ce2fac154..9d4cddb71b 100644 --- a/submodules/ton/tonlib-src/crypto/smartcont/wallet-code.fc +++ b/submodules/ton/tonlib-src/crypto/smartcont/wallet-code.fc @@ -29,3 +29,9 @@ int seqno() method_id { return get_data().begin_parse().preload_uint(32); } + +int get_public_key() method_id { + var cs = get_data().begin_parse(); + cs~load_uint(32); + return cs.preload_uint(256); +} diff --git a/submodules/ton/tonlib-src/crypto/smartcont/wallet-v2.fif b/submodules/ton/tonlib-src/crypto/smartcont/wallet-v2.fif index 3d36643b45..f01ca47e67 100755 --- a/submodules/ton/tonlib-src/crypto/smartcont/wallet-v2.fif +++ b/submodules/ton/tonlib-src/crypto/smartcont/wallet-v2.fif @@ -1,30 +1,52 @@ #!/usr/bin/fift -s "TonUtil.fif" include +"GetOpt.fif" include + +{ show-options-help 1 halt } : usage + +"" =: comment // comment for simple transfers +true =: allow-bounce +false =: force-bounce +3 =: send-mode // mode for SENDRAWMSG: +1 - sender pays fees, +2 - ignore errors +60 =: timeout // external message expires in 60 seconds + +begin-options + " [-n|-b] [-t] [-B ] [-C ] []" +cr +tab + +"Creates a request to advanced wallet created by new-wallet-v2.fif, with private key loaded from file .pk " + +"and address from .addr, and saves it into .boc ('wallet-query.boc' by default)" + disable-digit-options generic-help-setopt + "n" "--no-bounce" { false =: allow-bounce } short-long-option + "Clears bounce flag" option-help + "b" "--force-bounce" { true =: force-bounce } short-long-option + "Forces bounce flag" option-help + "t" "--timeout" { parse-int =: timeout } short-long-option-arg + "Sets expiration timeout in seconds (" timeout (.) $+ +" by default)" option-help + "B" "--body" { =: body-boc-file } short-long-option-arg + "Sets the payload of the transfer message" option-help + "C" "--comment" { =: comment } short-long-option-arg + "Sets the comment to be sent in the transfer message" option-help + "m" "--mode" { parse-int =: send-mode } short-long-option-arg + "Sets transfer mode (0..255) for SENDRAWMSG (" send-mode (.) $+ +" by default)" + option-help + "h" "--help" { usage } short-long-option + "Shows a help message" option-help +parse-options -{ ."usage: " @' $0 type ." [-B ] []" cr - ."Creates a request to advanced wallet created by new-wallet-v2.fif, with private key loaded from file .pk " - ."and address from .addr, and saves it into .boc ('wallet-query.boc' by default)" cr 1 halt -} : usage -def? $6 { @' $5 "-B" $= { @' $6 =: body-boc-file [forget] $6 def? $7 { @' $7 =: $5 [forget] $7 } { [forget] $5 } cond - @' $# 2- =: $# } if } if $# dup 4 < swap 5 > or ' usage if - +5 :$1..n true constant bounce - $1 =: file-base -$2 bounce parse-load-address =: bounce 2=: dest_addr +$2 bounce parse-load-address force-bounce or allow-bounce and =: bounce 2=: dest_addr $3 parse-int =: seqno $4 $>GR =: amount -def? $5 { @' $5 } { "wallet-query" } cond constant savefile -3 constant send-mode // mode for SENDRAWMSG: +1 - sender pays fees, +2 - ignore errors -60 constant timeout // external message expires in 60 seconds +$5 "wallet-query" replace-if-null =: savefile file-base +".addr" load-address 2dup 2constant wallet_addr ."Source wallet address = " 2dup .addr cr 6 .Addr cr file-base +".pk" load-keypair nip constant wallet_pk -def? body-boc-file { @' body-boc-file file>B B>boc } { } cond +def? body-boc-file { @' body-boc-file file>B B>boc } { comment simple-transfer-body } cond constant body-cell ."Transferring " amount .GR ."to account " @@ -33,8 +55,8 @@ dest_addr 2dup bounce 7 + .Addr ." = " .addr ."Body of transfer message is " body-cell dup ."signing message: " [-n|-b] [-t] [-B ] [-C ] []" +cr +tab + +"Creates a request to advanced wallet created by new-wallet-v3.fif, with private key loaded from file .pk " + +"and address from .addr, and saves it into .boc ('wallet-query.boc' by default)" + disable-digit-options generic-help-setopt + "n" "--no-bounce" { false =: allow-bounce } short-long-option + "Clears bounce flag" option-help + "b" "--force-bounce" { true =: force-bounce } short-long-option + "Forces bounce flag" option-help + "t" "--timeout" { parse-int =: timeout } short-long-option-arg + "Sets expiration timeout in seconds (" timeout (.) $+ +" by default)" option-help + "B" "--body" { =: body-boc-file } short-long-option-arg + "Sets the payload of the transfer message" option-help + "C" "--comment" { =: comment } short-long-option-arg + "Sets the comment to be sent in the transfer message" option-help + "m" "--mode" { parse-int =: send-mode } short-long-option-arg + "Sets transfer mode (0..255) for SENDRAWMSG (" send-mode (.) $+ +" by default)" + option-help + "h" "--help" { usage } short-long-option + "Shows a help message" option-help +parse-options -{ ."usage: " @' $0 type ." [-B ] []" cr - ."Creates a request to advanced wallet created by new-wallet-v3.fif, with private key loaded from file .pk " - ."and address from .addr, and saves it into .boc ('wallet-query.boc' by default)" cr 1 halt -} : usage -def? $7 { @' $6 "-B" $= { @' $7 =: body-boc-file [forget] $7 def? $8 { @' $8 =: $6 [forget] $8 } { [forget] $6 } cond - @' $# 2- =: $# } if } if $# dup 5 < swap 6 > or ' usage if +6 :$1..n true constant bounce - $1 =: file-base -$2 bounce parse-load-address =: bounce 2=: dest_addr +$2 bounce parse-load-address force-bounce or allow-bounce and =: bounce 2=: dest_addr $3 parse-int =: subwallet_id $4 parse-int =: seqno $5 $>GR =: amount -def? $6 { @' $6 } { "wallet-query" } cond constant savefile -3 constant send-mode // mode for SENDRAWMSG: +1 - sender pays fees, +2 - ignore errors -60 constant timeout // external message expires in 60 seconds +$6 "wallet-query" replace-if-null =: savefile file-base +".addr" load-address 2dup 2constant wallet_addr ."Source wallet address = " 2dup .addr cr 6 .Addr cr file-base +".pk" load-keypair nip constant wallet_pk -def? body-boc-file { @' body-boc-file file>B B>boc } { } cond +def? body-boc-file { @' body-boc-file file>B B>boc } { comment simple-transfer-body } cond constant body-cell ."Transferring " amount .GR ."to account " @@ -35,8 +58,8 @@ dest_addr 2dup bounce 7 + .Addr ." = " .addr ."Body of transfer message is " body-cell dup ."signing message: " [-B ] [-C ] []" cr - ."Creates a request to simple wallet created by new-wallet.fif, with private key loaded from file .pk " - ."and address from .addr, and saves it into .boc ('wallet-query.boc' by default)" cr 1 halt -} : usage "" =: comment // comment for simple transfers -def? $6 { @' $5 dup "-B" $= swap "-C" $= tuck or - { @' $6 swap { =: comment } { =: body-boc-file } cond [forget] $6 - def? $7 { @' $7 =: $5 [forget] $7 } { [forget] $5 } cond - @' $# 2- =: $# - } if -} if +true =: allow-bounce +false =: force-bounce +3 =: send-mode // mode for SENDRAWMSG: +1 - sender pays fees, +2 - ignore errors + +begin-options + " [-n|-b] [-B ] [-C ] []" +cr +tab + +"Creates a request to simple wallet created by new-wallet.fif, with private key loaded from file .pk " + +"and address from .addr, and saves it into .boc ('wallet-query.boc' by default)" + disable-digit-options generic-help-setopt + "n" "--no-bounce" { false =: allow-bounce } short-long-option + "Clears bounce flag" option-help + "b" "--force-bounce" { true =: force-bounce } short-long-option + "Forces bounce flag" option-help + "B" "--body" { =: body-boc-file } short-long-option-arg + "Sets the payload of the transfer message" option-help + "C" "--comment" { =: comment } short-long-option-arg + "Sets the comment to be sent in the transfer message" option-help + "m" "--mode" { parse-int =: send-mode } short-long-option-arg + "Sets transfer mode (0..255) for SENDRAWMSG (" send-mode (.) $+ +" by default)" + option-help + "h" "--help" { usage } short-long-option + "Shows a help message" option-help +parse-options + $# dup 4 < swap 5 > or ' usage if - -true constant bounce - +5 :$1..n +true =: bounce $1 =: file-base -$2 bounce parse-load-address =: bounce 2=: dest_addr +$2 bounce parse-load-address allow-bounce and force-bounce or =: bounce 2=: dest_addr $3 parse-int =: seqno $4 $>GR =: amount -def? $5 { @' $5 } { "wallet-query" } cond constant savefile -3 constant send-mode // mode for SENDRAWMSG: +1 - sender pays fees, +2 - ignore errors +$5 "wallet-query" replace-if-null =: savefile +allow-bounce not force-bounce and abort"cannot have bounce flag both set and cleared" // "" 1 { 69091 * 1+ 65535 and tuck 2521 / 65 + hold swap } 1000 times drop =: comment file-base +".addr" load-address @@ -38,8 +54,8 @@ dest_addr 2dup bounce 7 + .Addr ." = " .addr ."Body of transfer message is " body-cell dup ."signing message: " . + + Copyright 2017-2020 Telegram Systems LLP +*/ +#include "HighloadWallet.h" +#include "GenericAccount.h" +#include "SmartContractCode.h" + +#include "vm/boc.h" +#include "vm/cells/CellString.h" +#include "td/utils/base64.h" + +#include + +namespace ton { +td::Ref HighloadWallet::get_init_state(const td::Ed25519::PublicKey& public_key, + td::uint32 wallet_id) noexcept { + auto code = get_init_code(); + auto data = get_init_data(public_key, wallet_id); + return GenericAccount::get_init_state(std::move(code), std::move(data)); +} + +td::Ref HighloadWallet::get_init_message(const td::Ed25519::PrivateKey& private_key, + td::uint32 wallet_id) noexcept { + td::uint32 seqno = 0; + td::uint32 valid_until = std::numeric_limits::max(); + auto append_message = [&](auto&& cb) -> vm::CellBuilder& { + cb.store_long(wallet_id, 32).store_long(valid_until, 32).store_long(seqno, 32); + CHECK(cb.store_maybe_ref({})); + return cb; + }; + auto signature = private_key.sign(append_message(vm::CellBuilder()).finalize()->get_hash().as_slice()).move_as_ok(); + + return append_message(vm::CellBuilder().store_bytes(signature)).finalize(); +} + +td::Ref HighloadWallet::make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 wallet_id, + td::uint32 seqno, td::uint32 valid_until, + td::Span gifts) noexcept { + CHECK(gifts.size() <= max_gifts_size); + vm::Dictionary messages(16); + for (size_t i = 0; i < gifts.size(); i++) { + auto& gift = gifts[i]; + td::int32 send_mode = 3; + auto gramms = gift.gramms; + if (gramms == -1) { + gramms = 0; + send_mode += 128; + } + vm::CellBuilder cb; + GenericAccount::store_int_message(cb, gift.destination, gramms); + cb.store_bytes("\0\0\0\0", 4); + vm::CellString::store(cb, gift.message, 35 * 8).ensure(); + auto message_inner = cb.finalize(); + cb = {}; + cb.store_long(send_mode, 8).store_ref(message_inner); + auto key = messages.integer_key(td::make_refint(i), 16, false); + messages.set_builder(key.bits(), 16, cb); + } + + vm::CellBuilder cb; + cb.store_long(wallet_id, 32).store_long(valid_until, 32).store_long(seqno, 32); + CHECK(cb.store_maybe_ref(messages.get_root_cell())); + auto message_outer = cb.finalize(); + auto signature = private_key.sign(message_outer->get_hash().as_slice()).move_as_ok(); + return vm::CellBuilder().store_bytes(signature).append_cellslice(vm::load_cell_slice(message_outer)).finalize(); +} + +td::Ref HighloadWallet::get_init_code() noexcept { + return SmartContractCode::get_code(SmartContractCode::HighloadWalletV1); +} + +vm::CellHash HighloadWallet::get_init_code_hash() noexcept { + return get_init_code()->get_hash(); +} + +td::Ref HighloadWallet::get_init_data(const td::Ed25519::PublicKey& public_key, + td::uint32 wallet_id) noexcept { + return vm::CellBuilder() + .store_long(0, 32) + .store_long(wallet_id, 32) + .store_bytes(public_key.as_octet_string()) + .finalize(); +} + +td::Result HighloadWallet::get_seqno() const { + return TRY_VM(get_seqno_or_throw()); +} + +td::Result HighloadWallet::get_seqno_or_throw() const { + if (state_.data.is_null()) { + return 0; + } + //FIXME use get method + return static_cast(vm::load_cell_slice(state_.data).fetch_ulong(32)); +} + +td::Result HighloadWallet::get_wallet_id() const { + return TRY_VM(get_wallet_id_or_throw()); +} + +td::Result HighloadWallet::get_wallet_id_or_throw() const { + if (state_.data.is_null()) { + return 0; + } + //FIXME use get method + auto cs = vm::load_cell_slice(state_.data); + cs.skip_first(32); + return static_cast(cs.fetch_ulong(32)); +} + +td::Result HighloadWallet::get_public_key() const { + return TRY_VM(get_public_key_or_throw()); +} + +td::Result HighloadWallet::get_public_key_or_throw() const { + if (state_.data.is_null()) { + return td::Status::Error("data is null"); + } + //FIXME use get method + auto cs = vm::load_cell_slice(state_.data); + cs.skip_first(64); + td::SecureString res(td::Ed25519::PublicKey::LENGTH); + cs.fetch_bytes(res.as_mutable_slice().ubegin(), td::narrow_cast(res.size())); + return td::Ed25519::PublicKey(std::move(res)); +} + +} // namespace ton diff --git a/submodules/ton/tonlib-src/crypto/smc-envelope/HighloadWallet.h b/submodules/ton/tonlib-src/crypto/smc-envelope/HighloadWallet.h new file mode 100644 index 0000000000..e1db23efb0 --- /dev/null +++ b/submodules/ton/tonlib-src/crypto/smc-envelope/HighloadWallet.h @@ -0,0 +1,63 @@ +/* + This file is part of TON Blockchain Library. + + TON Blockchain Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + TON Blockchain Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with TON Blockchain Library. If not, see . + + Copyright 2017-2020 Telegram Systems LLP +*/ +#pragma once + +#include "smc-envelope/SmartContract.h" +#include "smc-envelope/WalletInterface.h" +#include "vm/cells.h" +#include "Ed25519.h" +#include "block/block.h" +#include "vm/cells/CellString.h" + +namespace ton { +class HighloadWallet : ton::SmartContract, public WalletInterface { + public: + explicit HighloadWallet(State state) : ton::SmartContract(std::move(state)) { + } + static constexpr unsigned max_message_size = vm::CellString::max_bytes; + static constexpr unsigned max_gifts_size = 254; + static td::Ref get_init_state(const td::Ed25519::PublicKey& public_key, td::uint32 wallet_id) noexcept; + static td::Ref get_init_message(const td::Ed25519::PrivateKey& private_key, td::uint32 wallet_id) noexcept; + static td::Ref make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 wallet_id, + td::uint32 seqno, td::uint32 valid_until, td::Span gifts) noexcept; + + static td::Ref get_init_code() noexcept; + static vm::CellHash get_init_code_hash() noexcept; + static td::Ref get_init_data(const td::Ed25519::PublicKey& public_key, td::uint32 wallet_id) noexcept; + + td::Result get_seqno() const; + td::Result get_wallet_id() const; + + td::Result> make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 valid_until, + td::Span gifts) const override { + TRY_RESULT(seqno, get_seqno()); + TRY_RESULT(wallet_id, get_wallet_id()); + return make_a_gift_message(private_key, wallet_id, seqno, valid_until, gifts); + } + size_t get_max_gifts_size() const override { + return max_gifts_size; + } + td::Result get_public_key() const override; + + private: + td::Result get_seqno_or_throw() const; + td::Result get_wallet_id_or_throw() const; + td::Result get_public_key_or_throw() const; +}; +} // namespace ton diff --git a/submodules/ton/tonlib-src/crypto/smc-envelope/HighloadWalletV2.cpp b/submodules/ton/tonlib-src/crypto/smc-envelope/HighloadWalletV2.cpp new file mode 100644 index 0000000000..dbdb52347a --- /dev/null +++ b/submodules/ton/tonlib-src/crypto/smc-envelope/HighloadWalletV2.cpp @@ -0,0 +1,151 @@ +/* + This file is part of TON Blockchain Library. + + TON Blockchain Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + TON Blockchain Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with TON Blockchain Library. If not, see . + + Copyright 2017-2020 Telegram Systems LLP +*/ +#include "HighloadWalletV2.h" +#include "GenericAccount.h" +#include "SmartContractCode.h" + +#include "vm/boc.h" +#include "vm/cells/CellString.h" +#include "td/utils/base64.h" + +#include + +namespace ton { +td::optional HighloadWalletV2::guess_revision(const vm::Cell::Hash& code_hash) { + for (td::int32 i = 1; i <= 2; i++) { + if (get_init_code(i)->get_hash() == code_hash) { + return i; + } + } + return {}; +} +td::optional HighloadWalletV2::guess_revision(const block::StdAddress& address, + const td::Ed25519::PublicKey& public_key, + td::uint32 wallet_id) { + for (td::int32 i = 1; i <= 2; i++) { + if (GenericAccount::get_address(address.workchain, get_init_state(public_key, wallet_id, i)) == address) { + return i; + } + } + return {}; +} +td::Ref HighloadWalletV2::get_init_state(const td::Ed25519::PublicKey& public_key, td::uint32 wallet_id, + td::int32 revision) noexcept { + auto code = get_init_code(revision); + auto data = get_init_data(public_key, wallet_id); + return GenericAccount::get_init_state(std::move(code), std::move(data)); +} + +td::Ref HighloadWalletV2::get_init_message(const td::Ed25519::PrivateKey& private_key, td::uint32 wallet_id, + td::uint32 valid_until) noexcept { + td::uint32 id = -1; + auto append_message = [&](auto&& cb) -> vm::CellBuilder& { + cb.store_long(wallet_id, 32).store_long(valid_until, 32).store_long(id, 32); + CHECK(cb.store_maybe_ref({})); + return cb; + }; + auto signature = private_key.sign(append_message(vm::CellBuilder()).finalize()->get_hash().as_slice()).move_as_ok(); + + return append_message(vm::CellBuilder().store_bytes(signature)).finalize(); +} + +td::Ref HighloadWalletV2::make_a_gift_message(const td::Ed25519::PrivateKey& private_key, + td::uint32 wallet_id, td::uint32 valid_until, + td::Span gifts) noexcept { + CHECK(gifts.size() <= max_gifts_size); + vm::Dictionary messages(16); + for (size_t i = 0; i < gifts.size(); i++) { + auto& gift = gifts[i]; + td::int32 send_mode = 3; + auto gramms = gift.gramms; + if (gramms == -1) { + gramms = 0; + send_mode += 128; + } + vm::CellBuilder cb; + GenericAccount::store_int_message(cb, gift.destination, gramms); + cb.store_bytes("\0\0\0\0", 4); + vm::CellString::store(cb, gift.message, 35 * 8).ensure(); + auto message_inner = cb.finalize(); + cb = {}; + cb.store_long(send_mode, 8).store_ref(message_inner); + auto key = messages.integer_key(td::make_refint(i), 16, false); + messages.set_builder(key.bits(), 16, cb); + } + std::string hash; + { + vm::CellBuilder cb; + CHECK(cb.store_maybe_ref(messages.get_root_cell())); + hash = cb.finalize()->get_hash().as_slice().substr(28, 4).str(); + } + + vm::CellBuilder cb; + cb.store_long(wallet_id, 32).store_long(valid_until, 32).store_bytes(hash); + CHECK(cb.store_maybe_ref(messages.get_root_cell())); + auto message_outer = cb.finalize(); + auto signature = private_key.sign(message_outer->get_hash().as_slice()).move_as_ok(); + return vm::CellBuilder().store_bytes(signature).append_cellslice(vm::load_cell_slice(message_outer)).finalize(); +} + +td::Ref HighloadWalletV2::get_init_code(td::int32 revision) noexcept { + return SmartContractCode::get_code(SmartContractCode::HighloadWalletV2, revision); +} + +vm::CellHash HighloadWalletV2::get_init_code_hash() noexcept { + return get_init_code(0)->get_hash(); +} + +td::Ref HighloadWalletV2::get_init_data(const td::Ed25519::PublicKey& public_key, + td::uint32 wallet_id) noexcept { + vm::CellBuilder cb; + cb.store_long(wallet_id, 32).store_long(0, 64).store_bytes(public_key.as_octet_string()); + CHECK(cb.store_maybe_ref({})); + return cb.finalize(); +} + +td::Result HighloadWalletV2::get_wallet_id() const { + return TRY_VM(get_wallet_id_or_throw()); +} + +td::Result HighloadWalletV2::get_wallet_id_or_throw() const { + if (state_.data.is_null()) { + return 0; + } + //FIXME use get method + auto cs = vm::load_cell_slice(state_.data); + return static_cast(cs.fetch_ulong(32)); +} + +td::Result HighloadWalletV2::get_public_key() const { + return TRY_VM(get_public_key_or_throw()); +} + +td::Result HighloadWalletV2::get_public_key_or_throw() const { + if (state_.data.is_null()) { + return td::Status::Error("data is null"); + } + //FIXME use get method + auto cs = vm::load_cell_slice(state_.data); + cs.skip_first(96); + td::SecureString res(td::Ed25519::PublicKey::LENGTH); + cs.fetch_bytes(res.as_mutable_slice().ubegin(), td::narrow_cast(res.size())); + return td::Ed25519::PublicKey(std::move(res)); +} + +} // namespace ton diff --git a/submodules/ton/tonlib-src/crypto/smc-envelope/HighloadWalletV2.h b/submodules/ton/tonlib-src/crypto/smc-envelope/HighloadWalletV2.h new file mode 100644 index 0000000000..2b6f99e7b0 --- /dev/null +++ b/submodules/ton/tonlib-src/crypto/smc-envelope/HighloadWalletV2.h @@ -0,0 +1,66 @@ +/* + This file is part of TON Blockchain Library. + + TON Blockchain Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + TON Blockchain Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with TON Blockchain Library. If not, see . + + Copyright 2017-2020 Telegram Systems LLP +*/ +#pragma once + +#include "smc-envelope/SmartContract.h" +#include "smc-envelope/WalletInterface.h" +#include "vm/cells.h" +#include "Ed25519.h" +#include "block/block.h" +#include "vm/cells/CellString.h" + +namespace ton { +class HighloadWalletV2 : ton::SmartContract, public WalletInterface { + public: + explicit HighloadWalletV2(State state) : ton::SmartContract(std::move(state)) { + } + static constexpr unsigned max_message_size = vm::CellString::max_bytes; + static constexpr unsigned max_gifts_size = 254; + static td::Ref get_init_state(const td::Ed25519::PublicKey& public_key, td::uint32 wallet_id, + td::int32 revision) noexcept; + static td::Ref get_init_message(const td::Ed25519::PrivateKey& private_key, td::uint32 wallet_id, + td::uint32 valid_until) noexcept; + + static td::Ref make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 wallet_id, + td::uint32 valid_until, td::Span gifts) noexcept; + + static td::Ref get_init_code(td::int32 revision) noexcept; + static vm::CellHash get_init_code_hash() noexcept; + static td::Ref get_init_data(const td::Ed25519::PublicKey& public_key, td::uint32 wallet_id) noexcept; + static td::optional guess_revision(const vm::Cell::Hash& code_hash); + static td::optional guess_revision(const block::StdAddress& address, + const td::Ed25519::PublicKey& public_key, td::uint32 wallet_id); + + td::Result get_wallet_id() const; + + td::Result> make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 valid_until, + td::Span gifts) const override { + TRY_RESULT(wallet_id, get_wallet_id()); + return make_a_gift_message(private_key, wallet_id, valid_until, gifts); + } + size_t get_max_gifts_size() const override { + return max_gifts_size; + } + td::Result get_public_key() const override; + + private: + td::Result get_wallet_id_or_throw() const; + td::Result get_public_key_or_throw() const; +}; +} // namespace ton diff --git a/submodules/ton/tonlib-src/crypto/smc-envelope/ManualDns.cpp b/submodules/ton/tonlib-src/crypto/smc-envelope/ManualDns.cpp new file mode 100644 index 0000000000..00f1becb88 --- /dev/null +++ b/submodules/ton/tonlib-src/crypto/smc-envelope/ManualDns.cpp @@ -0,0 +1,604 @@ +/* + This file is part of TON Blockchain Library. + + TON Blockchain Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + TON Blockchain Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with TON Blockchain Library. If not, see . + + Copyright 2019-2020 Telegram Systems LLP +*/ +#include "ManualDns.h" + +#include "smc-envelope/SmartContractCode.h" + +#include "vm/dict.h" + +#include "td/utils/format.h" +#include "td/utils/overloaded.h" +#include "td/utils/Parser.h" +#include "td/utils/Random.h" + +#include "block/block-auto.h" +#include "block/block-parse.h" + +#include "common/util.h" + +namespace ton { +td::StringBuilder& operator<<(td::StringBuilder& sb, const ManualDns::EntryData& data) { + switch (data.type) { + case ManualDns::EntryData::Type::Empty: + return sb << "DELETED"; + case ManualDns::EntryData::Type::Text: + return sb << "TEXT:" << data.data.get().text; + case ManualDns::EntryData::Type::NextResolver: + return sb << "NEXT:" << data.data.get().resolver.rserialize(); + case ManualDns::EntryData::Type::AdnlAddress: + return sb << "ADNL:" + << td::adnl_id_encode(data.data.get().adnl_address.as_slice()) + .move_as_ok(); + case ManualDns::EntryData::Type::SmcAddress: + return sb << "SMC:" << data.data.get().smc_address.rserialize(); + } + return sb << ""; +} + +//proto_list_nil$0 = ProtoList; +//proto_list_next$1 head:Protocol tail:ProtoList = ProtoList; +//proto_http#4854 = Protocol; + +//cap_list_nil$0 = SmcCapList; +//cap_list_next$1 head:SmcCapability tail:SmcCapList = SmcCapList; +//cap_method_seqno#5371 = SmcCapability; +//cap_method_pubkey#71f4 = SmcCapability; +//cap_is_wallet#2177 = SmcCapability; +//cap_name#ff name:Text = SmcCapability; +// +td::Result> DnsInterface::EntryData::as_cell() const { + td::Ref res; + td::Status error; + data.visit(td::overloaded( + [&](const EntryDataText& text) { + block::gen::DNSRecord::Record_dns_text dns; + vm::CellBuilder cb; + vm::CellText::store(cb, text.text); + dns.x = vm::load_cell_slice_ref(cb.finalize()); + tlb::pack_cell(res, dns); + }, + [&](const EntryDataNextResolver& resolver) { + block::gen::DNSRecord::Record_dns_next_resolver dns; + vm::CellBuilder cb; + block::tlb::t_MsgAddressInt.store_std_address(cb, resolver.resolver.workchain, resolver.resolver.addr); + dns.resolver = vm::load_cell_slice_ref(cb.finalize()); + tlb::pack_cell(res, dns); + }, + [&](const EntryDataAdnlAddress& adnl_address) { + block::gen::DNSRecord::Record_dns_adnl_address dns; + dns.adnl_addr = adnl_address.adnl_address; + dns.flags = 0; + tlb::pack_cell(res, dns); + }, + [&](const EntryDataSmcAddress& smc_address) { + block::gen::DNSRecord::Record_dns_smc_address dns; + vm::CellBuilder cb; + block::tlb::t_MsgAddressInt.store_std_address(cb, smc_address.smc_address.workchain, + smc_address.smc_address.addr); + dns.smc_addr = vm::load_cell_slice_ref(cb.finalize()); + tlb::pack_cell(res, dns); + })); + if (error.is_error()) { + return error; + } + if (res.is_null()) { + return td::Status::Error("Entry data is emtpy"); + } + return res; + //dns_text#1eda _:Text = DNSRecord; + + //dns_next_resolver#ba93 resolver:MsgAddressInt = DNSRecord; // usually in record #-1 + //dns_adnl_address#ad01 adnl_addr:bits256 flags:(## 8) { flags <= 1 } proto_list:flags . 0?ProtoList = DNSRecord; // often in record #2 + + //dns_smc_address#9fd3 smc_addr:MsgAddressInt flags:(## 8) { flags <= 1 } cap_list:flags . 0?SmcCapList = DNSRecord; // often in record #1 +} + +td::Result DnsInterface::EntryData::from_cellslice(vm::CellSlice& cs) { + switch (block::gen::t_DNSRecord.get_tag(cs)) { + case block::gen::DNSRecord::dns_text: { + block::gen::DNSRecord::Record_dns_text dns; + tlb::unpack(cs, dns); + TRY_RESULT(text, vm::CellText::load(dns.x.write())); + return EntryData::text(std::move(text)); + } + case block::gen::DNSRecord::dns_next_resolver: { + block::gen::DNSRecord::Record_dns_next_resolver dns; + tlb::unpack(cs, dns); + ton::WorkchainId wc; + ton::StdSmcAddress addr; + if (!block::tlb::t_MsgAddressInt.extract_std_address(dns.resolver, wc, addr)) { + return td::Status::Error("Invalid address"); + } + return EntryData::next_resolver(block::StdAddress(wc, addr)); + } + case block::gen::DNSRecord::dns_adnl_address: { + block::gen::DNSRecord::Record_dns_adnl_address dns; + tlb::unpack(cs, dns); + return EntryData::adnl_address(dns.adnl_addr); + } + case block::gen::DNSRecord::dns_smc_address: { + block::gen::DNSRecord::Record_dns_smc_address dns; + tlb::unpack(cs, dns); + ton::WorkchainId wc; + ton::StdSmcAddress addr; + if (!block::tlb::t_MsgAddressInt.extract_std_address(dns.smc_addr, wc, addr)) { + return td::Status::Error("Invalid address"); + } + return EntryData::smc_address(block::StdAddress(wc, addr)); + } + } + return td::Status::Error("Unknown entry data"); +} + +SmartContract::Args DnsInterface::resolve_args_raw(td::Slice encoded_name, td::int16 category) { + SmartContract::Args res; + res.set_method_id("dnsresolve"); + res.set_stack( + {vm::load_cell_slice_ref(vm::CellBuilder().store_bytes(encoded_name).finalize()), td::make_refint(category)}); + return res; +} + +td::Result DnsInterface::resolve_args(td::Slice name, td::int32 category_big) { + TRY_RESULT(category, td::narrow_cast_safe(category_big)); + if (name.size() > get_default_max_name_size()) { + return td::Status::Error("Name is too long"); + } + auto encoded_name = encode_name(name); + return resolve_args_raw(encoded_name, category); +} + +td::Result> DnsInterface::resolve(td::Slice name, td::int32 category) const { + TRY_RESULT(raw_entries, resolve_raw(name, category)); + std::vector entries; + entries.reserve(raw_entries.size()); + for (auto& raw_entry : raw_entries) { + Entry entry; + entry.name = std::move(raw_entry.name); + entry.category = raw_entry.category; + auto cs = vm::load_cell_slice(raw_entry.data); + TRY_RESULT(data, EntryData::from_cellslice(cs)); + entry.data = std::move(data); + entries.push_back(std::move(entry)); + } + return entries; +} + +/* + External message structure: + [Bytes<512b>:signature] [UInt<32b>:seqno] [UInt<6b>:operation] + [Either b0: inline name (<= 58-x Bytes) or b1: reference-stored name) + x depends on operation + Use of 6-bit op instead of 32-bit allows to save 4 bytes for inline name + Inline [Name] structure: [UInt<6b>:length] [Bytes:data] + Operations (continuation of message): + 00 Contract initialization message (only if seqno = 0) (x=-) + 31 TSet: replace ENTIRE DOMAIN TABLE with the provided tree root cell (x=-) + [Cell<1r>:new_domains_table] + 51 OSet: replace owner public key with a new one (x=-) + [UInt<256b>:new_public_key] +*/ +// creation +td::Ref ManualDns::create(td::Ref data, int revision) { + return td::Ref( + true, State{ton::SmartContractCode::get_code(ton::SmartContractCode::ManualDns, revision), std::move(data)}); +} + +td::Ref ManualDns::create(const td::Ed25519::PublicKey& public_key, td::uint32 wallet_id, int revision) { + return create(create_init_data_fast(public_key, wallet_id), revision); +} + +td::optional ManualDns::guess_revision(const vm::Cell::Hash& code_hash) { + for (auto i : ton::SmartContractCode::get_revisions(ton::SmartContractCode::ManualDns)) { + if (ton::SmartContractCode::get_code(ton::SmartContractCode::ManualDns, i)->get_hash() == code_hash) { + return i; + } + } + return {}; +} +td::optional ManualDns::guess_revision(const block::StdAddress& address, + const td::Ed25519::PublicKey& public_key, td::uint32 wallet_id) { + for (auto i : {-1, 1}) { + auto dns = ton::ManualDns::create(public_key, wallet_id, i); + if (dns->get_address() == address) { + return i; + } + } + return {}; +} + +td::Result ManualDns::get_wallet_id() const { + return TRY_VM(get_wallet_id_or_throw()); +} +td::Result ManualDns::get_wallet_id_or_throw() const { + if (state_.data.is_null()) { + return 0; + } + //FIXME use get method + return static_cast(vm::load_cell_slice(state_.data).fetch_ulong(32)); +} + +td::Result> ManualDns::create_set_value_unsigned(td::int16 category, td::Slice name, + td::Ref data) const { + //11 VSet: set specified value to specified subdomain->category (x=2) + //[Int<16b>:category] [Name:subdomain] [Cell<1r>:value] + vm::CellBuilder cb; + cb.store_long(11, 6); + if (name.size() <= 58 - 2) { + cb.store_long(category, 16); + cb.store_long(0, 1); + cb.store_long(name.size(), 6); + cb.store_bytes(name); + } else { + cb.store_long(category, 16); + cb.store_long(1, 1); + cb.store_ref(vm::CellBuilder().store_bytes(name).finalize()); + } + cb.store_maybe_ref(std::move(data)); + return cb.finalize(); +} +td::Result> ManualDns::create_delete_value_unsigned(td::int16 category, td::Slice name) const { + //12 VDel: delete specified subdomain->category (x=2) + //[Int<16b>:category] [Name:subdomain] + vm::CellBuilder cb; + cb.store_long(12, 6); + if (name.size() <= 58 - 2) { + cb.store_long(category, 16); + cb.store_long(0, 1); + cb.store_long(name.size(), 6); + cb.store_bytes(name); + } else { + cb.store_long(category, 16); + cb.store_long(1, 1); + cb.store_ref(vm::CellBuilder().store_bytes(name).finalize()); + } + return cb.finalize(); +} + +td::Result> ManualDns::create_delete_all_unsigned() const { + // 32 TDel: nullify ENTIRE DOMAIN TABLE (x=-) + vm::CellBuilder cb; + cb.store_long(32, 6); + return cb.finalize(); +} + +td::Result> ManualDns::create_set_all_unsigned(td::Span entries) const { + vm::PrefixDictionary pdict(1023); + for (auto& action : entries) { + auto name_key = encode_name(action.name); + int zero_cnt = 0; + for (auto c : name_key) { + if (c == 0) { + zero_cnt++; + } + } + auto new_name_key = vm::load_cell_slice(vm::CellBuilder().store_long(zero_cnt, 7).store_bytes(name_key).finalize()); + auto ptr = new_name_key.data_bits(); + auto ptr_size = new_name_key.size(); + auto o_dict = pdict.lookup(ptr, ptr_size); + td::Ref dict_root; + if (o_dict.not_null()) { + o_dict->prefetch_maybe_ref(dict_root); + } + vm::Dictionary dict(dict_root, 16); + if (!action.data.value().is_null()) { + auto key = dict.integer_key(td::make_refint(action.category), 16); + dict.set_ref(key.bits(), 16, action.data.value()); + } + pdict.set(ptr, ptr_size, dict.get_root()); + } + + vm::CellBuilder cb; + cb.store_long(31, 6); + + cb.store_maybe_ref(pdict.get_root_cell()); + + return cb.finalize(); +} + +//21 DSet: replace entire category dictionary of domain with provided (x=0) +//[Name:subdomain] [Cell<1r>:new_cat_table] +//22 DDel: delete entire category dictionary of specified domain (x=0) +//[Name:subdomain] +td::Result> ManualDns::create_delete_name_unsigned(td::Slice name) const { + vm::CellBuilder cb; + cb.store_long(22, 6); + if (name.size() <= 58) { + cb.store_long(0, 1); + cb.store_long(name.size(), 6); + cb.store_bytes(name); + } else { + cb.store_long(1, 1); + cb.store_ref(vm::CellBuilder().store_bytes(name).finalize()); + } + return cb.finalize(); +} +td::Result> ManualDns::create_set_name_unsigned(td::Slice name, td::Span entries) const { + vm::CellBuilder cb; + cb.store_long(21, 6); + if (name.size() <= 58) { + cb.store_long(0, 1); + cb.store_long(name.size(), 6); + cb.store_bytes(name); + } else { + cb.store_long(1, 1); + cb.store_ref(vm::CellBuilder().store_bytes(name).finalize()); + } + + vm::Dictionary dict(16); + + for (auto& action : entries) { + if (action.data.value().is_null()) { + continue; + } + auto key = dict.integer_key(td::make_refint(action.category), 16); + dict.set_ref(key.bits(), 16, action.data.value()); + } + cb.store_maybe_ref(dict.get_root_cell()); + + return cb.finalize(); +} + +td::Result> ManualDns::prepare(td::Ref data, td::uint32 valid_until) const { + TRY_RESULT(wallet_id, get_wallet_id()); + auto hash = data->get_hash().as_slice().substr(28, 4).str(); + + vm::CellBuilder cb; + cb.store_long(wallet_id, 32).store_long(valid_until, 32); + //cb.store_bytes(hash); + cb.store_long(td::Random::secure_uint32(), 32); + cb.append_cellslice(vm::load_cell_slice(data)); + return cb.finalize(); +} + +td::Result> ManualDns::sign(const td::Ed25519::PrivateKey& private_key, td::Ref data) { + auto signature = private_key.sign(data->get_hash().as_slice()).move_as_ok(); + vm::CellBuilder cb; + cb.store_bytes(signature.as_slice()); + cb.append_cellslice(vm::load_cell_slice(data)); + return cb.finalize(); +} + +td::Result> ManualDns::create_init_query(const td::Ed25519::PrivateKey& private_key, + td::uint32 valid_until) const { + vm::CellBuilder cb; + cb.store_long(0, 6); + + TRY_RESULT(prepared, prepare(cb.finalize(), valid_until)); + return sign(private_key, std::move(prepared)); +} + +td::Ref ManualDns::create_init_data_fast(const td::Ed25519::PublicKey& public_key, td::uint32 wallet_id) { + vm::CellBuilder cb; + cb.store_long(wallet_id, 32).store_long(0, 64).store_bytes(public_key.as_octet_string()); + CHECK(cb.store_maybe_ref({})); + CHECK(cb.store_maybe_ref({})); + return cb.finalize(); +} + +size_t ManualDns::get_max_name_size() const { + return get_default_max_name_size(); +} + +td::Result> ManualDns::resolve_raw(td::Slice name, td::int32 category_big) const { + return TRY_VM(resolve_raw_or_throw(name, category_big)); +} +td::Result> ManualDns::resolve_raw_or_throw(td::Slice name, + td::int32 category_big) const { + TRY_RESULT(category, td::narrow_cast_safe(category_big)); + if (name.size() > get_max_name_size()) { + return td::Status::Error("Name is too long"); + } + auto encoded_name = encode_name(name); + auto res = run_get_method(resolve_args_raw(encoded_name, category)); + if (!res.success) { + return td::Status::Error("get method failed"); + } + std::vector vec; + auto data = res.stack.write().pop_maybe_cell(); + if (data.is_null()) { + return vec; + } + size_t prefix_size = res.stack.write().pop_smallint_range((int)encoded_name.size() * 8); + if (prefix_size % 8 != 0) { + return td::Status::Error("Prefix size is not divisible by 8"); + } + prefix_size /= 8; + if (prefix_size < encoded_name.size()) { + vec.push_back({decode_name(td::Slice(encoded_name).substr(0, prefix_size)), -1, data}); + } else { + if (category == 0) { + vm::Dictionary dict(std::move(data), 16); + dict.check_for_each([&](auto cs, auto x, auto y) { + td::BigInt256 cat; + cat.import_bits(x, y, true); + vec.push_back({name.str(), td::narrow_cast(cat.to_long()), cs->prefetch_ref()}); + return true; + }); + } else { + vec.push_back({name.str(), category, data}); + } + } + + return vec; +} + +td::Result> ManualDns::create_update_query(CombinedActions& combined) const { + if (combined.name.empty()) { + if (combined.actions.value().empty()) { + return create_delete_all_unsigned(); + } + return create_set_all_unsigned(combined.actions.value()); + } + if (combined.category == 0) { + if (!combined.actions) { + return create_delete_name_unsigned(encode_name(combined.name)); + } + return create_set_name_unsigned(encode_name(combined.name), combined.actions.value()); + } + CHECK(combined.actions.value().size() == 1); + auto& action = combined.actions.value()[0]; + if (action.data) { + return create_set_value_unsigned(action.category, encode_name(action.name), action.data.value()); + } else { + return create_delete_value_unsigned(action.category, encode_name(action.name)); + } +} + +td::Result> ManualDns::create_update_query(td::Ed25519::PrivateKey& pk, td::Span actions, + td::uint32 valid_until) const { + auto combined = combine_actions(actions); + std::vector> queries; + for (auto& c : combined) { + TRY_RESULT(q, create_update_query(c)); + queries.push_back(std::move(q)); + } + + td::Ref combined_query; + for (auto& query : td::reversed(queries)) { + if (combined_query.is_null()) { + combined_query = std::move(query); + } else { + auto next = vm::load_cell_slice(combined_query); + combined_query = vm::CellBuilder() + .append_cellslice(vm::load_cell_slice(query)) + .store_ref(vm::CellBuilder().append_cellslice(next).finalize()) + .finalize(); + } + } + + TRY_RESULT(prepared, prepare(std::move(combined_query), valid_until)); + return sign(pk, std::move(prepared)); +} + +std::string DnsInterface::encode_name(td::Slice name) { + std::string res; + while (!name.empty()) { + auto pos = name.rfind('.'); + if (pos == name.npos) { + res += name.str(); + name = td::Slice(); + } else { + res += name.substr(pos + 1).str(); + name.truncate(pos); + } + res += '\0'; + } + return res; +} + +std::string DnsInterface::decode_name(td::Slice name) { + std::string res; + if (!name.empty() && name.back() == 0) { + name.remove_suffix(1); + } + while (!name.empty()) { + auto pos = name.rfind('\0'); + if (!res.empty()) { + res += '.'; + } + if (pos == name.npos) { + res += name.str(); + name = td::Slice(); + } else { + res += name.substr(pos + 1).str(); + name.truncate(pos); + } + } + return res; +} + +std::string ManualDns::serialize_data(const EntryData& data) { + std::string res; + data.data.visit(td::overloaded([&](const ton::ManualDns::EntryDataText& text) { res = "UNSUPPORTED"; }, + [&](const ton::ManualDns::EntryDataNextResolver& resolver) { res = "UNSUPPORTED"; }, + [&](const ton::ManualDns::EntryDataAdnlAddress& adnl_address) { res = "UNSUPPORTED"; }, + [&](const ton::ManualDns::EntryDataSmcAddress& text) { res = "UNSUPPORTED"; })); + return res; +} + +td::Result> ManualDns::parse_data(td::Slice cmd) { + td::ConstParser parser(cmd); + parser.skip_whitespaces(); + auto type = parser.read_till(':'); + parser.skip(':'); + if (type == "TEXT") { + return ManualDns::EntryData::text(parser.read_all().str()); + } else if (type == "ADNL") { + TRY_RESULT(address, td::adnl_id_decode(parser.read_all())); + return ManualDns::EntryData::adnl_address(address); + } else if (type == "SMC") { + TRY_RESULT(address, block::StdAddress::parse(parser.read_all())); + return ManualDns::EntryData::smc_address(address); + } else if (type == "NEXT") { + TRY_RESULT(address, block::StdAddress::parse(parser.read_all())); + return ManualDns::EntryData::next_resolver(address); + } else if (parser.data() == "DELETED") { + return {}; + } + return td::Status::Error(PSLICE() << "Unknown entry type: " << type); +} + +td::Result ManualDns::parse_line(td::Slice cmd) { + // Cmd = + // set name category data | + // delete.name name | + // delete.all + // data = + // TEXT: | + // SMC: | + // NEXT: | + // ADNL: + // DELETED + td::ConstParser parser(cmd); + auto type = parser.read_word(); + if (type == "set") { + auto name = parser.read_word(); + auto category_str = parser.read_word(); + TRY_RESULT(category, td::to_integer_safe(category_str)); + TRY_RESULT(data, parse_data(parser.read_all())); + return ManualDns::ActionExt{name.str(), category, std::move(data)}; + } else if (type == "delete.name") { + auto name = parser.read_word(); + if (name.empty()) { + return td::Status::Error("name is empty"); + } + return ManualDns::ActionExt{name.str(), 0, {}}; + } else if (type == "delete.all") { + return ManualDns::ActionExt{"", 0, {}}; + } + return td::Status::Error(PSLICE() << "Unknown command: " << type); +} + +td::Result> ManualDns::parse(td::Slice cmd) { + auto lines = td::full_split(cmd, '\n'); + std::vector res; + res.reserve(lines.size()); + for (auto& line : lines) { + td::ConstParser parser(line); + parser.skip_whitespaces(); + if (parser.empty()) { + continue; + } + TRY_RESULT(action, parse_line(parser.read_all())); + res.push_back(std::move(action)); + } + return res; +} + +} // namespace ton diff --git a/submodules/ton/tonlib-src/crypto/smc-envelope/ManualDns.h b/submodules/ton/tonlib-src/crypto/smc-envelope/ManualDns.h new file mode 100644 index 0000000000..fbf12e74c7 --- /dev/null +++ b/submodules/ton/tonlib-src/crypto/smc-envelope/ManualDns.h @@ -0,0 +1,335 @@ +/* + This file is part of TON Blockchain Library. + + TON Blockchain Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + TON Blockchain Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with TON Blockchain Library. If not, see . + + Copyright 2019-2020 Telegram Systems LLP +*/ +#pragma once +#include "td/utils/Variant.h" +#include "td/utils/Status.h" +#include "vm/cells/Cell.h" +#include "vm/cells/CellSlice.h" +#include "vm/cells/CellString.h" + +#include "smc-envelope/SmartContract.h" + +#include "Ed25519.h" + +#include + +namespace ton { +class DnsInterface { + public: + struct EntryDataText { + std::string text; + bool operator==(const EntryDataText& other) const { + return text == other.text; + } + }; + + struct EntryDataNextResolver { + block::StdAddress resolver; + bool operator==(const EntryDataNextResolver& other) const { + return resolver == other.resolver; + } + }; + + struct EntryDataAdnlAddress { + ton::Bits256 adnl_address; + // TODO: proto + bool operator==(const EntryDataAdnlAddress& other) const { + return adnl_address == other.adnl_address; + } + }; + + struct EntryDataSmcAddress { + block::StdAddress smc_address; + bool operator==(const EntryDataSmcAddress& other) const { + return smc_address == other.smc_address; + } + // TODO: capability + }; + + struct EntryData { + enum Type { Empty, Text, NextResolver, AdnlAddress, SmcAddress } type{Empty}; + td::Variant data; + + static EntryData text(std::string text) { + return {Text, EntryDataText{text}}; + } + static EntryData next_resolver(block::StdAddress resolver) { + return {NextResolver, EntryDataNextResolver{resolver}}; + } + static EntryData adnl_address(ton::Bits256 adnl_address) { + return {AdnlAddress, EntryDataAdnlAddress{adnl_address}}; + } + static EntryData smc_address(block::StdAddress smc_address) { + return {SmcAddress, EntryDataSmcAddress{smc_address}}; + } + + bool operator==(const EntryData& other) const { + return data == other.data; + } + friend td::StringBuilder& operator<<(td::StringBuilder& sb, const EntryData& data); + + td::Result> as_cell() const; + static td::Result from_cellslice(vm::CellSlice& cs); + }; + + struct Entry { + std::string name; + td::int16 category; + EntryData data; + auto key() const { + return std::tie(name, category); + } + bool operator<(const Entry& other) const { + return key() < other.key(); + } + bool operator==(const Entry& other) const { + return key() == other.key() && data == other.data; + } + friend td::StringBuilder& operator<<(td::StringBuilder& sb, const Entry& entry) { + sb << entry.name << ":" << entry.category << ":" << entry.data; + return sb; + } + }; + struct RawEntry { + std::string name; + td::int16 category; + td::Ref data; + }; + + struct ActionExt { + std::string name; + td::int16 category; + td::optional data; + static td::Result parse(td::Slice); + }; + + struct Action { + std::string name; + td::int16 category; + td::optional> data; + + bool does_create_category() const { + CHECK(!name.empty()); + CHECK(category != 0); + return static_cast(data); + } + bool does_change_empty() const { + CHECK(!name.empty()); + CHECK(category != 0); + return static_cast(data) && data.value().not_null(); + } + void make_non_empty() { + CHECK(!name.empty()); + CHECK(category != 0); + if (!data) { + data = td::Ref(); + } + } + friend td::StringBuilder& operator<<(td::StringBuilder& sb, const Action& action) { + sb << action.name << ":" << action.category << ":"; + if (action.data) { + if (action.data.value().is_null()) { + sb << ""; + } else { + sb << ""; + } + } else { + sb << ""; + } + return sb; + } + }; + + virtual ~DnsInterface() { + } + virtual size_t get_max_name_size() const = 0; + virtual td::Result> resolve_raw(td::Slice name, td::int32 category) const = 0; + virtual td::Result> create_update_query( + td::Ed25519::PrivateKey& pk, td::Span actions, + td::uint32 valid_until = std::numeric_limits::max()) const = 0; + + td::Result> resolve(td::Slice name, td::int32 category) const; + + static std::string encode_name(td::Slice name); + static std::string decode_name(td::Slice name); + + static size_t get_default_max_name_size() { + return 128; + } + static SmartContract::Args resolve_args_raw(td::Slice encoded_name, td::int16 category); + static td::Result resolve_args(td::Slice name, td::int32 category); +}; + +class ManualDns : public ton::SmartContract, public DnsInterface { + public: + ManualDns(State state) : SmartContract(std::move(state)) { + } + + ManualDns* make_copy() const override { + return new ManualDns{state_}; + } + + // creation + static td::Ref create(State state) { + return td::Ref(true, std::move(state)); + } + static td::Ref create(td::Ref data = {}, int revision = 0); + static td::Ref create(const td::Ed25519::PublicKey& public_key, td::uint32 wallet_id, int revision = 0); + + static std::string serialize_data(const EntryData& data); + static td::Result> parse_data(td::Slice cmd); + static td::Result parse_line(td::Slice cmd); + static td::Result> parse(td::Slice cmd); + + static td::optional guess_revision(const vm::Cell::Hash& code_hash); + static td::optional guess_revision(const block::StdAddress& address, + const td::Ed25519::PublicKey& public_key, td::uint32 wallet_id); + + td::Ref create_init_data(const td::Ed25519::PublicKey& public_key, td::uint32 valid_until) const { + return create_init_data_fast(public_key, valid_until); + } + + td::Result get_wallet_id() const; + td::Result get_wallet_id_or_throw() const; + + td::Result> create_set_value_unsigned(td::int16 category, td::Slice name, + td::Ref data) const; + td::Result> create_delete_value_unsigned(td::int16 category, td::Slice name) const; + td::Result> create_delete_all_unsigned() const; + td::Result> create_set_all_unsigned(td::Span entries) const; + td::Result> create_delete_name_unsigned(td::Slice name) const; + td::Result> create_set_name_unsigned(td::Slice name, td::Span entries) const; + + td::Result> prepare(td::Ref data, td::uint32 valid_until) const; + + static td::Result> sign(const td::Ed25519::PrivateKey& private_key, td::Ref data); + static td::Ref create_init_data_fast(const td::Ed25519::PublicKey& public_key, td::uint32 wallet_id); + + size_t get_max_name_size() const override; + td::Result> resolve_raw(td::Slice name, td::int32 category_big) const override; + td::Result> resolve_raw_or_throw(td::Slice name, td::int32 category_big) const; + + td::Result> create_init_query( + const td::Ed25519::PrivateKey& private_key, + td::uint32 valid_until = std::numeric_limits::max()) const; + td::Result> create_update_query( + td::Ed25519::PrivateKey& pk, td::Span actions, + td::uint32 valid_until = std::numeric_limits::max()) const override; + + template + struct CombinedActions { + std::string name; + td::int16 category{0}; + td::optional> actions; + friend td::StringBuilder& operator<<(td::StringBuilder& sb, const CombinedActions& action) { + sb << action.name << ":" << action.category << ":"; + if (action.actions) { + sb << "" << action.actions.value().size(); + } else { + sb << ""; + } + return sb; + } + }; + + template + static std::vector> combine_actions(td::Span actions) { + struct Info { + std::set known_category; + std::vector actions; + bool closed{false}; + bool non_empty{false}; + }; + + std::map mp; + std::vector> res; + for (auto& action : td::reversed(actions)) { + if (action.name.empty()) { + CombinedActions set_all; + set_all.actions = std::vector(); + for (auto& it : mp) { + for (auto& e : it.second.actions) { + if (e.does_create_category()) { + set_all.actions.value().push_back(std::move(e)); + } + } + } + res.push_back(std::move(set_all)); + return res; + } + + Info& info = mp[action.name]; + if (info.closed) { + continue; + } + if (action.category != 0 && action.does_create_category()) { + info.non_empty = true; + } + if (!info.known_category.insert(action.category).second) { + continue; + } + if (action.category == 0) { + info.closed = true; + auto old_actions = std::move(info.actions); + bool is_empty = true; + for (auto& action : old_actions) { + if (is_empty && action.does_create_category()) { + info.actions.push_back(std::move(action)); + is_empty = false; + } else if (!is_empty && action.does_change_empty()) { + info.actions.push_back(std::move(action)); + } + } + } else { + info.actions.push_back(std::move(action)); + } + } + + for (auto& it : mp) { + auto& info = it.second; + if (info.closed) { + CombinedActions ca; + ca.name = it.first; + ca.category = 0; + if (!info.actions.empty() || info.non_empty) { + ca.actions = std::move(info.actions); + } + res.push_back(std::move(ca)); + } else { + bool need_non_empty = info.non_empty; + for (auto& a : info.actions) { + if (need_non_empty) { + a.make_non_empty(); + need_non_empty = false; + } + CombinedActions ca; + ca.name = a.name; + ca.category = a.category; + ca.actions = std::vector(); + ca.actions.value().push_back(std::move(a)); + res.push_back(ca); + } + } + } + return res; + } + td::Result> create_update_query(CombinedActions& combined) const; +}; + +} // namespace ton diff --git a/submodules/ton/tonlib-src/crypto/smc-envelope/MultisigWallet.cpp b/submodules/ton/tonlib-src/crypto/smc-envelope/MultisigWallet.cpp index 36830179c5..5a9fab6a82 100644 --- a/submodules/ton/tonlib-src/crypto/smc-envelope/MultisigWallet.cpp +++ b/submodules/ton/tonlib-src/crypto/smc-envelope/MultisigWallet.cpp @@ -1,3 +1,21 @@ +/* + This file is part of TON Blockchain Library. + + TON Blockchain Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + TON Blockchain Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with TON Blockchain Library. If not, see . + + Copyright 2019-2020 Telegram Systems LLP +*/ #include "MultisigWallet.h" #include "SmartContractCode.h" @@ -8,8 +26,13 @@ namespace ton { -MultisigWallet::QueryBuilder::QueryBuilder(td::int64 query_id, td::Ref msg, int mode) { - msg_ = vm::CellBuilder().store_long(query_id, 64).store_long(mode, 8).store_ref(std::move(msg)).finalize(); +MultisigWallet::QueryBuilder::QueryBuilder(td::uint32 wallet_id, td::int64 query_id, td::Ref msg, int mode) { + msg_ = vm::CellBuilder() + .store_long(wallet_id, 32) + .store_long(query_id, 64) + .store_long(mode, 8) + .store_ref(std::move(msg)) + .finalize(); } void MultisigWallet::QueryBuilder::sign(td::int32 id, td::Ed25519::PrivateKey& pk) { CHECK(id < td::narrow_cast(mask_.size())); @@ -43,7 +66,8 @@ td::Ref MultisigWallet::QueryBuilder::create(td::int32 id, td::Ed25519 } td::Ref MultisigWallet::create(td::Ref data) { - return td::Ref(true, State{ton::SmartContractCode::multisig(), std::move(data)}); + return td::Ref( + true, State{ton::SmartContractCode::get_code(ton::SmartContractCode::Multisig), std::move(data)}); } int MultisigWallet::processed(td::uint64 query_id) const { @@ -87,26 +111,29 @@ std::vector MultisigWallet::get_public_keys() const { return res; } -td::Ref MultisigWallet::create_init_data(std::vector public_keys, int k) const { +td::Ref MultisigWallet::create_init_data(td::uint32 wallet_id, std::vector public_keys, + int k) const { vm::Dictionary pk(8); for (size_t i = 0; i < public_keys.size(); i++) { auto key = pk.integer_key(td::make_refint(i), 8, false); - pk.set_builder(key.bits(), 8, vm::CellBuilder().store_bytes(public_keys[i].as_slice())); + pk.set_builder(key.bits(), 8, vm::CellBuilder().store_bytes(public_keys[i].as_slice()).store_long(0, 8)); } - auto res = run_get_method("create_init_state", - {td::make_refint(public_keys.size()), td::make_refint(k), pk.get_root_cell()}); + auto res = run_get_method("create_init_state", {td::make_refint(wallet_id), td::make_refint(public_keys.size()), + td::make_refint(k), pk.get_root_cell()}); CHECK(res.code == 0); return res.stack.write().pop_cell(); } -td::Ref MultisigWallet::create_init_data_fast(std::vector public_keys, int k) { +td::Ref MultisigWallet::create_init_data_fast(td::uint32 wallet_id, std::vector public_keys, + int k) { vm::Dictionary pk(8); for (size_t i = 0; i < public_keys.size(); i++) { auto key = pk.integer_key(td::make_refint(i), 8, false); - pk.set_builder(key.bits(), 8, vm::CellBuilder().store_bytes(public_keys[i].as_slice())); + pk.set_builder(key.bits(), 8, vm::CellBuilder().store_bytes(public_keys[i].as_slice()).store_long(0, 8)); } vm::CellBuilder cb; + cb.store_long(wallet_id, 32); cb.store_long(public_keys.size(), 8).store_long(k, 8).store_long(0, 64); cb.ensure_throw(cb.store_maybe_ref(pk.get_root_cell())); cb.ensure_throw(cb.store_maybe_ref({})); @@ -156,7 +183,7 @@ std::vector MultisigWallet::get_unsigned_messaged(int i vm::Dictionary dict(std::move(cell), 64); std::vector res; dict.check_for_each([&](auto cs, auto ptr, auto ptr_bits) { - cs.write().skip_first(8); + cs.write().skip_first(8 + 8); Message message; td::BigInt256 query_id; query_id.import_bits(ptr, ptr_bits, false); diff --git a/submodules/ton/tonlib-src/crypto/smc-envelope/MultisigWallet.h b/submodules/ton/tonlib-src/crypto/smc-envelope/MultisigWallet.h index 10c6d07604..96da297a4f 100644 --- a/submodules/ton/tonlib-src/crypto/smc-envelope/MultisigWallet.h +++ b/submodules/ton/tonlib-src/crypto/smc-envelope/MultisigWallet.h @@ -1,3 +1,21 @@ +/* + This file is part of TON Blockchain Library. + + TON Blockchain Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + TON Blockchain Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with TON Blockchain Library. If not, see . + + Copyright 2019-2020 Telegram Systems LLP +*/ #pragma once #include "vm/cells.h" @@ -20,7 +38,7 @@ class MultisigWallet : public ton::SmartContract { class QueryBuilder { public: - QueryBuilder(td::int64 query_id, td::Ref msg, int mode = 3); + QueryBuilder(td::uint32 wallet_id, td::int64 query_id, td::Ref msg, int mode = 3); void sign(td::int32 id, td::Ed25519::PrivateKey& pk); td::Ref create_inner() const; @@ -42,8 +60,9 @@ class MultisigWallet : public ton::SmartContract { // creation static td::Ref create(td::Ref data = {}); - td::Ref create_init_data(std::vector public_keys, int k) const; - static td::Ref create_init_data_fast(std::vector public_keys, int k); + td::Ref create_init_data(td::uint32 wallet_id, std::vector public_keys, int k) const; + static td::Ref create_init_data_fast(td::uint32 wallet_id, std::vector public_keys, + int k); // get methods int processed(td::uint64 query_id) const; diff --git a/submodules/ton/tonlib-src/crypto/smc-envelope/SmartContract.cpp b/submodules/ton/tonlib-src/crypto/smc-envelope/SmartContract.cpp index ea76423763..36ba273043 100644 --- a/submodules/ton/tonlib-src/crypto/smc-envelope/SmartContract.cpp +++ b/submodules/ton/tonlib-src/crypto/smc-envelope/SmartContract.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "SmartContract.h" @@ -24,23 +24,21 @@ #include "block/block-auto.h" #include "vm/cellslice.h" #include "vm/cp0.h" -#include "vm/continuation.h" +#include "vm/memo.h" +#include "vm/vm.h" #include "td/utils/crypto.h" namespace ton { namespace { -td::int32 get_method_id(td::Slice method_name) { - unsigned crc = td::crc16(method_name); - return (crc & 0xffff) | 0x10000; -} + td::Ref prepare_vm_stack(td::Ref body) { td::Ref stack_ref{true}; td::RefInt256 acc_addr{true}; //CHECK(acc_addr.write().import_bits(account.addr.cbits(), 256)); vm::Stack& stack = stack_ref.write(); - stack.push_int(td::RefInt256{true, 10000000000}); - stack.push_int(td::RefInt256{true, 10000000000}); + stack.push_int(td::make_refint(10000000000)); + stack.push_int(td::make_refint(10000000000)); stack.push_cell(vm::CellBuilder().finalize()); stack.push_cellslice(std::move(body)); return stack_ref; @@ -94,6 +92,11 @@ SmartContract::Answer run_smartcont(SmartContract::State state, td::Ref= VERBOSITY_NAME(DEBUG)) { + std::ostringstream os; + stack->dump(os, 2); + LOG(DEBUG) << "VM stack:\n" << os.str(); + } vm::VmState vm{state.code, std::move(stack), gas, 1, state.data, log}; vm.set_c7(std::move(c7)); vm.set_chksig_always_succeed(ignore_chksig); @@ -111,7 +114,7 @@ SmartContract::Answer run_smartcont(SmartContract::State state, td::Ref= VERBOSITY_NAME(DEBUG)) { LOG(DEBUG) << "VM log\n" << logger.res; std::ostringstream os; - res.stack->dump(os); + res.stack->dump(os, 2); LOG(DEBUG) << "VM stack:\n" << os.str(); LOG(DEBUG) << "VM exit code: " << res.code; LOG(DEBUG) << "VM accepted: " << res.accepted; @@ -128,6 +131,21 @@ SmartContract::Answer run_smartcont(SmartContract::State state, td::Ref SmartContract::Args::get_serialized_stack() { + if (!stack) { + return td::Status::Error("Args has no stack"); + } + vm::FakeVmStateLimits fstate(1000); // limit recursive (de)serialization calls + vm::VmStateInterface::Guard guard(&fstate); + // serialize parameters + vm::CellBuilder cb; + td::Ref cell; + if (!(stack.value()->serialize(cb) && cb.finalize_to(cell))) { + return td::Status::Error("Cannot serialize stack in args"); + } + return vm::std_boc_serialize(std::move(cell)); +} + td::Ref SmartContract::empty_slice() { return vm::load_cell_slice_ref(vm::CellBuilder().finalize()); } diff --git a/submodules/ton/tonlib-src/crypto/smc-envelope/SmartContract.h b/submodules/ton/tonlib-src/crypto/smc-envelope/SmartContract.h index d586436195..24c2d13232 100644 --- a/submodules/ton/tonlib-src/crypto/smc-envelope/SmartContract.h +++ b/submodules/ton/tonlib-src/crypto/smc-envelope/SmartContract.h @@ -14,13 +14,13 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once #include "vm/cells.h" #include "vm/stack.hpp" -#include "vm/continuation.h" +#include "vm/vm.h" #include "td/utils/optional.h" #include "td/utils/crypto.h" @@ -90,6 +90,14 @@ class SmartContract : public td::CntObject { this->ignore_chksig = ignore_chksig; return std::move(*this); } + + td::Result get_method_id() const { + if (!method_id) { + return td::Status::Error("Args has no method id"); + } + return method_id.value(); + } + td::Result get_serialized_stack(); }; Answer run_method(Args args = {}); diff --git a/submodules/ton/tonlib-src/crypto/smc-envelope/SmartContractCode.cpp b/submodules/ton/tonlib-src/crypto/smc-envelope/SmartContractCode.cpp index c187131d71..6256dcc064 100644 --- a/submodules/ton/tonlib-src/crypto/smc-envelope/SmartContractCode.cpp +++ b/submodules/ton/tonlib-src/crypto/smc-envelope/SmartContractCode.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "SmartContractCode.h" @@ -25,13 +25,15 @@ namespace ton { namespace { +// WALLET_REVISION = 2; +// WALLET2_REVISION = 2; +// WALLET3_REVISION = 2; +// HIGHLOAD_WALLET_REVISION = 2; +// HIGHLOAD_WALLET2_REVISION = 2; +// DNS_REVISION = 1; const auto& get_map() { static auto map = [] { - class Cmp : public std::less<> { - public: - using is_transparent = void; - }; - std::map, Cmp> map; + std::map, std::less<>> map; auto with_tvm_code = [&](auto name, td::Slice code_str) { map[name] = vm::std_boc_deserialize(td::base64_decode(code_str).move_as_ok()).move_as_ok(); }; @@ -39,6 +41,61 @@ const auto& get_map() { #include "smartcont/auto/simple-wallet-ext-code.cpp" #include "smartcont/auto/simple-wallet-code.cpp" #include "smartcont/auto/wallet-code.cpp" +#include "smartcont/auto/highload-wallet-code.cpp" +#include "smartcont/auto/highload-wallet-v2-code.cpp" +#include "smartcont/auto/dns-manual-code.cpp" + + with_tvm_code("highload-wallet-r1", + "te6ccgEBBgEAhgABFP8A9KQT9KDyyAsBAgEgAgMCAUgEBQC88oMI1xgg0x/TH9Mf+CMTu/Jj7UTQ0x/TH9P/" + "0VEyuvKhUUS68qIE+QFUEFX5EPKj9ATR+AB/jhghgBD0eG+hb6EgmALTB9QwAfsAkTLiAbPmWwGkyMsfyx/L/" + "8ntVAAE0DAAEaCZL9qJoa4WPw=="); + with_tvm_code("highload-wallet-r2", + "te6ccgEBCAEAlwABFP8A9KQT9LzyyAsBAgEgAgMCAUgEBQC48oMI1xgg0x/TH9Mf+CMTu/Jj7UTQ0x/TH9P/" + "0VEyuvKhUUS68qIE+QFUEFX5EPKj9ATR+AB/jhYhgBD0eG+lIJgC0wfUMAH7AJEy4gGz5lsBpMjLH8sfy//" + "J7VQABNAwAgFIBgcAF7s5ztRNDTPzHXC/+AARuMl+1E0NcLH4"); + with_tvm_code("highload-wallet-v2-r1", + "te6ccgEBBwEA1gABFP8A9KQT9KDyyAsBAgEgAgMCAUgEBQHu8oMI1xgg0x/TP/gjqh9TILnyY+1E0NMf0z/T//" + "QE0VNggED0Dm+hMfJgUXO68qIH+QFUEIf5EPKjAvQE0fgAf44YIYAQ9HhvoW+" + "hIJgC0wfUMAH7AJEy4gGz5luDJaHIQDSAQPRDiuYxyBLLHxPLP8v/9ADJ7VQGAATQMABBoZfl2omhpj5jpn+n/" + "mPoCaKkQQCB6BzfQmMktv8ld0fFADgggED0lm+hb6EyURCUMFMDud4gkzM2AZIyMOKz"); + with_tvm_code("highload-wallet-v2-r2", + "te6ccgEBCQEA5QABFP8A9KQT9LzyyAsBAgEgAgMCAUgEBQHq8oMI1xgg0x/TP/gjqh9TILnyY+1E0NMf0z/T//" + "QE0VNggED0Dm+hMfJgUXO68qIH+QFUEIf5EPKjAvQE0fgAf44WIYAQ9HhvpSCYAtMH1DAB+wCRMuIBs+" + "ZbgyWhyEA0gED0Q4rmMcgSyx8Tyz/L//QAye1UCAAE0DACASAGBwAXvZznaiaGmvmOuF/8AEG+X5dqJoaY+Y6Z/p/" + "5j6AmipEEAgegc30JjJLb/JXdHxQANCCAQPSWb6UyURCUMFMDud4gkzM2AZIyMOKz"); + with_tvm_code("simple-wallet-r1", + "te6ccgEEAQEAAAAAUwAAov8AIN0gggFMl7qXMO1E0NcLH+Ck8mCBAgDXGCDXCx/tRNDTH9P/" + "0VESuvKhIvkBVBBE+RDyovgAAdMfMSDXSpbTB9QC+wDe0aTIyx/L/8ntVA=="); + with_tvm_code("simple-wallet-r2", + "te6ccgEBAQEAXwAAuv8AIN0gggFMl7ohggEznLqxnHGw7UTQ0x/XC//jBOCk8mCBAgDXGCDXCx/tRNDTH9P/" + "0VESuvKhIvkBVBBE+RDyovgAAdMfMSDXSpbTB9QC+wDe0aTIyx/L/8ntVA=="); + with_tvm_code("wallet-r1", + "te6ccgEBAQEAVwAAqv8AIN0gggFMl7qXMO1E0NcLH+Ck8mCDCNcYINMf0x8B+CO78mPtRNDTH9P/0VExuvKhA/" + "kBVBBC+RDyovgAApMg10qW0wfUAvsA6NGkyMsfy//J7VQ="); + with_tvm_code("wallet-r2", + "te6ccgEBAQEAYwAAwv8AIN0gggFMl7ohggEznLqxnHGw7UTQ0x/XC//jBOCk8mCDCNcYINMf0x8B+CO78mPtRNDTH9P/" + "0VExuvKhA/kBVBBC+RDyovgAApMg10qW0wfUAvsA6NGkyMsfy//J7VQ="); + with_tvm_code("wallet3-r1", + "te6ccgEBAQEAYgAAwP8AIN0gggFMl7qXMO1E0NcLH+Ck8mCDCNcYINMf0x/TH/gjE7vyY+1E0NMf0x/T/" + "9FRMrryoVFEuvKiBPkBVBBV+RDyo/gAkyDXSpbTB9QC+wDo0QGkyMsfyx/L/8ntVA=="); + with_tvm_code("wallet3-r2", + "te6ccgEBAQEAcQAA3v8AIN0gggFMl7ohggEznLqxn3Gw7UTQ0x/THzHXC//jBOCk8mCDCNcYINMf0x/TH/gjE7vyY+1E0NMf0x/" + "T/9FRMrryoVFEuvKiBPkBVBBV+RDyo/gAkyDXSpbTB9QC+wDo0QGkyMsfyx/L/8ntVA=="); + with_tvm_code( + "dns-manual-r1", + "te6ccgECGAEAAtAAART/APSkE/S88sgLAQIBIAIDAgFIBAUC7PLbPAWDCNcYIPkBAdMf0z/" + "4I6ofUyC58mNTKoBA9A5voTHyYFKUuvKiVBNG+RDyo/gAItcLBcAzmDQBdtch0/" + "8wjoVa2zxAA+" + "IDgyWhyEAHgED0Q44aIIBA9JZvpTJREJQwUwe53iCTMzUBkjIw4rPmNVUD8AQREgICxQYHAgEgDA0CAc8ICQAIqoJfAwIBSAoLACHWQK5Y+" + "J5Z/l//oAegBk9qpAAFF8DgABcyPQAydBBM/Rw8qGAAF72c52omhpr5jrhf/" + "AIBIA4PABG7Nz7UTQ1wsfgD+" + "7owwh10kglF8DcG3hIHew8l4ieNci1wsHnnDIUATPFhPLB8nQAqYI3iDACJRfA3Bt4Ns8FF8EI3ADqwKY0wcBwAAToQLkIG2OnF8DIcjLBiTPF" + "snQhAlUQgHbPAWlFbIgwQEVQzDmMzUilF8FcG3hMgHHAJMxfwHfAtdJpvmBEVEAAYIcAAkjEB4AKAEPRqABztRNDTH9M/0//" + "0BPQE0QE2cFmOlNs8IMcBnCDXSpPUMNCTMn8C4t4i5jAxEwT20wUhwQqOLCGRMeEhwAGXMdMH1AL7AOABwAmOFNQh+wTtQwLQ7R7tU1RiA/" + "EGgvIA4PIt4HAiwRSUMNIPAd5tbSTBHoreJMEUjpElhAkj2zwzApUyxwDyo5Fb4t4kwAuOEzQC9ARQJIAQ9G4wECOECVnwAQHgJMAMiuAwFBUW" + "FwCEMQLTAAHAAZPUAdCY0wUBqgLXGAHiINdJwg/" + "ypiB41yLXCwfyaHBTEddJqTYCmNMHAcAAEqEB5DDIywYBzxbJ0FADACBZ9KhvpSCUAvQEMJIybeICACg0A4AQ9FqZECOECUBE8AEBkjAx4gBmM" + "SLAFZwy9AQQI4QJUELwAQHgIsAWmDIChAn0czAB4DAyIMAfkzD0BODAIJJtAeDyLG0B"); return map; }(); return map; @@ -49,24 +106,97 @@ td::Result> SmartContractCode::load(td::Slice name) { auto& map = get_map(); auto it = map.find(name); if (it == map.end()) { - return td::Status::Error(PSLICE() << "Can't load td::ref " << name); } return it->second; } -td::Ref SmartContractCode::multisig() { - auto res = load("multisig").move_as_ok(); - return res; + +td::Span SmartContractCode::get_revisions(Type type) { + switch (type) { + case Type::WalletV1: { + static int res[] = {1, 2}; + return res; + } + case Type::WalletV2: { + static int res[] = {1, 2}; + return res; + } + case Type::WalletV3: { + static int res[] = {1, 2}; + return res; + } + case Type::WalletV1Ext: { + static int res[] = {-1}; + return res; + } + case Type::HighloadWalletV1: { + static int res[] = {-1, 1, 2}; + return res; + } + case Type::HighloadWalletV2: { + static int res[] = {-1, 1, 2}; + return res; + } + case Type::Multisig: { + static int res[] = {-1}; + return res; + } + case Type::ManualDns: { + static int res[] = {-1, 1}; + return res; + } + } + UNREACHABLE(); + return {}; } -td::Ref SmartContractCode::wallet() { - auto res = load("wallet").move_as_ok(); - return res; + +td::Result SmartContractCode::validate_revision(Type type, int revision) { + auto revisions = get_revisions(type); + if (revision == -1) { + if (revisions[0] == -1) { + return -1; + } + return revisions[revisions.size() - 1]; + } + if (revision == 0) { + return revisions[revisions.size() - 1]; + } + for (auto x : revisions) { + if (x == revision) { + return revision; + } + } + return td::Status::Error("No such revision"); } -td::Ref SmartContractCode::simple_wallet() { - auto res = load("simple-wallet").move_as_ok(); - return res; -} -td::Ref SmartContractCode::simple_wallet_ext() { - static auto res = load("simple-wallet-ext").move_as_ok(); - return res; + +td::Ref SmartContractCode::get_code(Type type, int ext_revision) { + auto revision = validate_revision(type, ext_revision).move_as_ok(); + auto basename = [](Type type) -> td::Slice { + switch (type) { + case Type::WalletV1: + return "simple-wallet"; + case Type::WalletV2: + return "wallet"; + case Type::WalletV3: + return "wallet3"; + case Type::WalletV1Ext: + return "simple-wallet-ext"; + case Type::HighloadWalletV1: + return "highload-wallet"; + case Type::HighloadWalletV2: + return "highload-wallet-v2"; + case Type::Multisig: + return "multisig"; + case Type::ManualDns: + return "dns-manual"; + } + UNREACHABLE(); + return ""; + }(type); + if (revision == -1) { + return load(basename).move_as_ok(); + } + return load(PSLICE() << basename << "-r" << revision).move_as_ok(); } + } // namespace ton diff --git a/submodules/ton/tonlib-src/crypto/smc-envelope/SmartContractCode.h b/submodules/ton/tonlib-src/crypto/smc-envelope/SmartContractCode.h index 059215e445..1ea2274c84 100644 --- a/submodules/ton/tonlib-src/crypto/smc-envelope/SmartContractCode.h +++ b/submodules/ton/tonlib-src/crypto/smc-envelope/SmartContractCode.h @@ -14,17 +14,20 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "vm/cells.h" +#include "td/utils/Span.h" + namespace ton { class SmartContractCode { public: static td::Result> load(td::Slice name); - static td::Ref multisig(); - static td::Ref wallet(); - static td::Ref simple_wallet(); - static td::Ref simple_wallet_ext(); + + enum Type { WalletV1 = 1, WalletV1Ext, WalletV2, WalletV3, HighloadWalletV1, HighloadWalletV2, ManualDns, Multisig }; + static td::Span get_revisions(Type type); + static td::Result validate_revision(Type type, int revision); + static td::Ref get_code(Type type, int revision = 0); }; } // namespace ton diff --git a/submodules/ton/tonlib-src/crypto/smc-envelope/TestGiver.cpp b/submodules/ton/tonlib-src/crypto/smc-envelope/TestGiver.cpp index 2d44d73073..f9ed60bfd7 100644 --- a/submodules/ton/tonlib-src/crypto/smc-envelope/TestGiver.cpp +++ b/submodules/ton/tonlib-src/crypto/smc-envelope/TestGiver.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "TestGiver.h" #include "GenericAccount.h" @@ -35,14 +35,23 @@ vm::CellHash TestGiver::get_init_code_hash() noexcept { //return vm::CellHash::from_slice(td::base64_decode("YV/IANhoI22HVeatFh6S5LbCHp+5OilARfzW+VQPZgQ=").move_as_ok()); } -td::Ref TestGiver::make_a_gift_message(td::uint32 seqno, td::uint64 gramms, td::Slice message, - const block::StdAddress& dest_address) noexcept { +td::Ref TestGiver::make_a_gift_message_static(td::uint32 seqno, td::Span gifts) noexcept { + CHECK(gifts.size() <= max_gifts_size); + vm::CellBuilder cb; - GenericAccount::store_int_message(cb, dest_address, gramms); - cb.store_bytes("\0\0\0\0", 4); - vm::CellString::store(cb, message, 35 * 8).ensure(); - auto message_inner = cb.finalize(); - return vm::CellBuilder().store_long(seqno, 32).store_long(1, 8).store_ref(message_inner).finalize(); + cb.store_long(seqno, 32); + + for (auto& gift : gifts) { + td::int32 send_mode = 1; + auto gramms = gift.gramms; + vm::CellBuilder cbi; + GenericAccount::store_int_message(cbi, gift.destination, gramms); + store_gift_message(cbi, gift); + auto message_inner = cbi.finalize(); + cb.store_long(send_mode, 8).store_ref(std::move(message_inner)); + } + + return cb.finalize(); } td::Result TestGiver::get_seqno() const { diff --git a/submodules/ton/tonlib-src/crypto/smc-envelope/TestGiver.h b/submodules/ton/tonlib-src/crypto/smc-envelope/TestGiver.h index 210b691240..b51ac7dbe0 100644 --- a/submodules/ton/tonlib-src/crypto/smc-envelope/TestGiver.h +++ b/submodules/ton/tonlib-src/crypto/smc-envelope/TestGiver.h @@ -14,25 +14,38 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once #include "SmartContract.h" +#include "smc-envelope/WalletInterface.h" #include "block/block.h" #include "vm/cells/CellString.h" namespace ton { -class TestGiver : public SmartContract { +class TestGiver : public SmartContract, public WalletInterface { public: explicit TestGiver(State state) : ton::SmartContract(std::move(state)) { } + TestGiver() : ton::SmartContract({}) { + } static constexpr unsigned max_message_size = vm::CellString::max_bytes; + static constexpr unsigned max_gifts_size = 1; static const block::StdAddress& address() noexcept; static vm::CellHash get_init_code_hash() noexcept; - static td::Ref make_a_gift_message(td::uint32 seqno, td::uint64 gramms, td::Slice message, - const block::StdAddress& dest_address) noexcept; + static td::Ref make_a_gift_message_static(td::uint32 seqno, td::Span) noexcept; td::Result get_seqno() const; + using WalletInterface::get_init_message; + td::Result> make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 valid_until, + td::Span gifts) const override { + TRY_RESULT(seqno, get_seqno()); + return make_a_gift_message_static(seqno, gifts); + } + size_t get_max_gifts_size() const override { + return max_gifts_size; + } + private: td::Result get_seqno_or_throw() const; }; diff --git a/submodules/ton/tonlib-src/crypto/smc-envelope/TestWallet.cpp b/submodules/ton/tonlib-src/crypto/smc-envelope/TestWallet.cpp index 1edf59f911..4f4dcd8dc2 100644 --- a/submodules/ton/tonlib-src/crypto/smc-envelope/TestWallet.cpp +++ b/submodules/ton/tonlib-src/crypto/smc-envelope/TestWallet.cpp @@ -13,17 +13,19 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . -Copyright 2017-2019 Telegram Systems LLP +Copyright 2017-2020 Telegram Systems LLP */ #include "TestWallet.h" #include "GenericAccount.h" +#include "SmartContractCode.h" + #include "vm/boc.h" #include "td/utils/base64.h" namespace ton { -td::Ref TestWallet::get_init_state(const td::Ed25519::PublicKey& public_key) noexcept { - auto code = get_init_code(); +td::Ref TestWallet::get_init_state(const td::Ed25519::PublicKey& public_key, td::int32 revision) noexcept { + auto code = get_init_code(revision); auto data = get_init_data(public_key); return GenericAccount::get_init_state(std::move(code), std::move(data)); } @@ -35,42 +37,46 @@ td::Ref TestWallet::get_init_message(const td::Ed25519::PrivateKey& pr return vm::CellBuilder().store_bytes(signature).store_bytes(seq_no).finalize(); } -td::Ref TestWallet::make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 seqno, - td::int64 gramms, td::Slice message, - const block::StdAddress& dest_address) noexcept { - td::int32 send_mode = 3; - if (gramms == -1) { - gramms = 0; - send_mode += 128; - } +td::Ref TestWallet::make_a_gift_message_static(const td::Ed25519::PrivateKey& private_key, td::uint32 seqno, + td::Span gifts) noexcept { + CHECK(gifts.size() <= max_gifts_size); + vm::CellBuilder cb; - GenericAccount::store_int_message(cb, dest_address, gramms); - cb.store_bytes("\0\0\0\0", 4); - vm::CellString::store(cb, message, 35 * 8).ensure(); - auto message_inner = cb.finalize(); - auto message_outer = - vm::CellBuilder().store_long(seqno, 32).store_long(send_mode, 8).store_ref(message_inner).finalize(); + cb.store_long(seqno, 32); + + for (auto& gift : gifts) { + td::int32 send_mode = 3; + auto gramms = gift.gramms; + if (gramms == -1) { + gramms = 0; + send_mode += 128; + } + vm::CellBuilder cbi; + GenericAccount::store_int_message(cbi, gift.destination, gramms); + store_gift_message(cbi, gift); + auto message_inner = cbi.finalize(); + cb.store_long(send_mode, 8).store_ref(std::move(message_inner)); + } + + auto message_outer = cb.finalize(); auto signature = private_key.sign(message_outer->get_hash().as_slice()).move_as_ok(); return vm::CellBuilder().store_bytes(signature).append_cellslice(vm::load_cell_slice(message_outer)).finalize(); } -td::Ref TestWallet::get_init_code() noexcept { - static auto res = [] { - auto serialized_code = td::base64_decode( - "te6ccgEEAQEAAAAAUwAAov8AIN0gggFMl7qXMO1E0NcLH+Ck8mCBAgDXGCDXCx/tRNDTH9P/" - "0VESuvKhIvkBVBBE+RDyovgAAdMfMSDXSpbTB9QC+wDe0aTIyx/L/8ntVA==") - .move_as_ok(); - return vm::std_boc_deserialize(serialized_code).move_as_ok(); - }(); - return res; +td::Ref TestWallet::get_init_code(td::int32 revision) noexcept { + return ton::SmartContractCode::get_code(ton::SmartContractCode::WalletV1, revision); } vm::CellHash TestWallet::get_init_code_hash() noexcept { return get_init_code()->get_hash(); } +td::Ref TestWallet::get_data(const td::Ed25519::PublicKey& public_key, td::uint32 seqno) noexcept { + return vm::CellBuilder().store_long(seqno, 32).store_bytes(public_key.as_octet_string()).finalize(); +} + td::Ref TestWallet::get_init_data(const td::Ed25519::PublicKey& public_key) noexcept { - return vm::CellBuilder().store_long(0, 32).store_bytes(public_key.as_octet_string()).finalize(); + return get_data(public_key, 0); } td::Result TestWallet::get_seqno() const { @@ -88,4 +94,20 @@ td::Result TestWallet::get_seqno_or_throw() const { return static_cast(seqno); } +td::Result TestWallet::get_public_key() const { + return TRY_VM(get_public_key_or_throw()); +} + +td::Result TestWallet::get_public_key_or_throw() const { + if (state_.data.is_null()) { + return td::Status::Error("data is null"); + } + //FIXME use get method + auto cs = vm::load_cell_slice(state_.data); + cs.skip_first(32); + td::SecureString res(td::Ed25519::PublicKey::LENGTH); + cs.fetch_bytes(res.as_mutable_slice().ubegin(), td::narrow_cast(res.size())); + return td::Ed25519::PublicKey(std::move(res)); +} + } // namespace ton diff --git a/submodules/ton/tonlib-src/crypto/smc-envelope/TestWallet.h b/submodules/ton/tonlib-src/crypto/smc-envelope/TestWallet.h index 161aef58b5..46891aa961 100644 --- a/submodules/ton/tonlib-src/crypto/smc-envelope/TestWallet.h +++ b/submodules/ton/tonlib-src/crypto/smc-envelope/TestWallet.h @@ -14,35 +14,53 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once #include "smc-envelope/SmartContract.h" +#include "smc-envelope/WalletInterface.h" #include "vm/cells.h" #include "Ed25519.h" #include "block/block.h" #include "vm/cells/CellString.h" namespace ton { -class TestWallet : public ton::SmartContract { +class TestWallet : public ton::SmartContract, public WalletInterface { public: explicit TestWallet(State state) : ton::SmartContract(std::move(state)) { } + explicit TestWallet(const td::Ed25519::PublicKey& public_key, td::uint32 seqno) + : TestWallet(State{get_init_code(), get_data(public_key, seqno)}) { + } static constexpr unsigned max_message_size = vm::CellString::max_bytes; - static td::Ref get_init_state(const td::Ed25519::PublicKey& public_key) noexcept; + static constexpr unsigned max_gifts_size = 1; + static td::Ref get_init_state(const td::Ed25519::PublicKey& public_key, td::int32 revision = 0) noexcept; static td::Ref get_init_message(const td::Ed25519::PrivateKey& private_key) noexcept; - static td::Ref make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 seqno, - td::int64 gramms, td::Slice message, - const block::StdAddress& dest_address) noexcept; + static td::Ref make_a_gift_message_static(const td::Ed25519::PrivateKey& private_key, td::uint32 seqno, + td::Span gifts) noexcept; - static td::Ref get_init_code() noexcept; + static td::Ref get_init_code(td::int32 revision = 0) noexcept; static vm::CellHash get_init_code_hash() noexcept; + static td::Ref get_data(const td::Ed25519::PublicKey& public_key, td::uint32 seqno) noexcept; static td::Ref get_init_data(const td::Ed25519::PublicKey& public_key) noexcept; td::Result get_seqno() const; + using WalletInterface::get_init_message; + td::Result> make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 valid_until, + td::Span gifts) const override { + TRY_RESULT(seqno, get_seqno()); + return make_a_gift_message_static(private_key, seqno, gifts); + } + size_t get_max_gifts_size() const override { + return max_gifts_size; + } + + td::Result get_public_key() const override; + private: td::Result get_seqno_or_throw() const; + td::Result get_public_key_or_throw() const; }; } // namespace ton diff --git a/submodules/ton/tonlib-src/crypto/smc-envelope/Wallet.cpp b/submodules/ton/tonlib-src/crypto/smc-envelope/Wallet.cpp index 61958ed959..ef637fb96c 100644 --- a/submodules/ton/tonlib-src/crypto/smc-envelope/Wallet.cpp +++ b/submodules/ton/tonlib-src/crypto/smc-envelope/Wallet.cpp @@ -14,10 +14,11 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "Wallet.h" #include "GenericAccount.h" +#include "SmartContractCode.h" #include "vm/boc.h" #include "vm/cells/CellString.h" @@ -26,8 +27,8 @@ #include namespace ton { -td::Ref Wallet::get_init_state(const td::Ed25519::PublicKey& public_key) noexcept { - auto code = get_init_code(); +td::Ref Wallet::get_init_state(const td::Ed25519::PublicKey& public_key, td::int32 revision) noexcept { + auto code = get_init_code(revision); auto data = get_init_data(public_key); return GenericAccount::get_init_state(std::move(code), std::move(data)); } @@ -43,46 +44,45 @@ td::Ref Wallet::get_init_message(const td::Ed25519::PrivateKey& privat } td::Ref Wallet::make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 seqno, - td::uint32 valid_until, td::int64 gramms, td::Slice message, - const block::StdAddress& dest_address) noexcept { - td::int32 send_mode = 3; - if (gramms == -1) { - gramms = 0; - send_mode += 128; - } - vm::CellBuilder cb; - GenericAccount::store_int_message(cb, dest_address, gramms); - cb.store_bytes("\0\0\0\0", 4); - vm::CellString::store(cb, message, 35 * 8).ensure(); - auto message_inner = cb.finalize(); + td::uint32 valid_until, td::Span gifts) noexcept { + CHECK(gifts.size() <= max_gifts_size); - auto message_outer = vm::CellBuilder() - .store_long(seqno, 32) - .store_long(valid_until, 32) - .store_long(send_mode, 8) - .store_ref(message_inner) - .finalize(); + vm::CellBuilder cb; + cb.store_long(seqno, 32).store_long(valid_until, 32); + + for (auto& gift : gifts) { + td::int32 send_mode = 3; + auto gramms = gift.gramms; + if (gramms == -1) { + gramms = 0; + send_mode += 128; + } + vm::CellBuilder cbi; + GenericAccount::store_int_message(cbi, gift.destination, gramms); + store_gift_message(cbi, gift); + auto message_inner = cbi.finalize(); + cb.store_long(send_mode, 8).store_ref(std::move(message_inner)); + } + + auto message_outer = cb.finalize(); auto signature = private_key.sign(message_outer->get_hash().as_slice()).move_as_ok(); return vm::CellBuilder().store_bytes(signature).append_cellslice(vm::load_cell_slice(message_outer)).finalize(); } -td::Ref Wallet::get_init_code() noexcept { - static auto res = [] { - auto serialized_code = td::base64_decode( - "te6ccgEEAQEAAAAAVwAAqv8AIN0gggFMl7qXMO1E0NcLH+Ck8mCDCNcYINMf0x8B+CO78mPtRNDTH9P/" - "0VExuvKhA/kBVBBC+RDyovgAApMg10qW0wfUAvsA6NGkyMsfy//J7VQ=") - .move_as_ok(); - return vm::std_boc_deserialize(serialized_code).move_as_ok(); - }(); - return res; +td::Ref Wallet::get_init_code(td::int32 revision) noexcept { + return SmartContractCode::get_code(ton::SmartContractCode::WalletV2, revision); } vm::CellHash Wallet::get_init_code_hash() noexcept { return get_init_code()->get_hash(); } +td::Ref Wallet::get_data(const td::Ed25519::PublicKey& public_key, td::uint32 seqno) noexcept { + return vm::CellBuilder().store_long(seqno, 32).store_bytes(public_key.as_octet_string()).finalize(); +} + td::Ref Wallet::get_init_data(const td::Ed25519::PublicKey& public_key) noexcept { - return vm::CellBuilder().store_long(0, 32).store_bytes(public_key.as_octet_string()).finalize(); + return get_data(public_key, 0); } td::Result Wallet::get_seqno() const { @@ -97,4 +97,20 @@ td::Result Wallet::get_seqno_or_throw() const { return static_cast(vm::load_cell_slice(state_.data).fetch_ulong(32)); } +td::Result Wallet::get_public_key() const { + return TRY_VM(get_public_key_or_throw()); +} + +td::Result Wallet::get_public_key_or_throw() const { + if (state_.data.is_null()) { + return td::Status::Error("data is null"); + } + //FIXME use get method + auto cs = vm::load_cell_slice(state_.data); + cs.skip_first(32); + td::SecureString res(td::Ed25519::PublicKey::LENGTH); + cs.fetch_bytes(res.as_mutable_slice().ubegin(), td::narrow_cast(res.size())); + return td::Ed25519::PublicKey(std::move(res)); +} + } // namespace ton diff --git a/submodules/ton/tonlib-src/crypto/smc-envelope/Wallet.h b/submodules/ton/tonlib-src/crypto/smc-envelope/Wallet.h index 7cd33c81d1..2299be7cca 100644 --- a/submodules/ton/tonlib-src/crypto/smc-envelope/Wallet.h +++ b/submodules/ton/tonlib-src/crypto/smc-envelope/Wallet.h @@ -14,35 +14,53 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once #include "smc-envelope/SmartContract.h" +#include "smc-envelope/WalletInterface.h" #include "vm/cells.h" #include "Ed25519.h" #include "block/block.h" #include "vm/cells/CellString.h" namespace ton { -class Wallet : ton::SmartContract { +class Wallet : ton::SmartContract, public WalletInterface { public: explicit Wallet(State state) : ton::SmartContract(std::move(state)) { } + explicit Wallet(const td::Ed25519::PublicKey& public_key, td::uint32 seqno) + : Wallet(State{get_init_code(), get_data(public_key, seqno)}) { + } static constexpr unsigned max_message_size = vm::CellString::max_bytes; - static td::Ref get_init_state(const td::Ed25519::PublicKey& public_key) noexcept; + static constexpr unsigned max_gifts_size = 4; + static td::Ref get_init_state(const td::Ed25519::PublicKey& public_key, td::int32 revision = 0) noexcept; static td::Ref get_init_message(const td::Ed25519::PrivateKey& private_key) noexcept; static td::Ref make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 seqno, - td::uint32 valid_until, td::int64 gramms, td::Slice message, - const block::StdAddress& dest_address) noexcept; + td::uint32 valid_until, td::Span gifts) noexcept; - static td::Ref get_init_code() noexcept; + static td::Ref get_init_code(td::int32 revision = 0) noexcept; static vm::CellHash get_init_code_hash() noexcept; static td::Ref get_init_data(const td::Ed25519::PublicKey& public_key) noexcept; + static td::Ref get_data(const td::Ed25519::PublicKey& public_key, td::uint32 seqno) noexcept; td::Result get_seqno() const; + using WalletInterface::get_init_message; + td::Result> make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 valid_until, + td::Span gifts) const override { + TRY_RESULT(seqno, get_seqno()); + return make_a_gift_message(private_key, seqno, valid_until, gifts); + } + size_t get_max_gifts_size() const override { + return max_gifts_size; + } + + td::Result get_public_key() const override; + private: td::Result get_seqno_or_throw() const; + td::Result get_public_key_or_throw() const; }; } // namespace ton diff --git a/submodules/ton/tonlib-src/crypto/smc-envelope/WalletInterface.h b/submodules/ton/tonlib-src/crypto/smc-envelope/WalletInterface.h new file mode 100644 index 0000000000..2c7760a1af --- /dev/null +++ b/submodules/ton/tonlib-src/crypto/smc-envelope/WalletInterface.h @@ -0,0 +1,72 @@ +/* + This file is part of TON Blockchain Library. + + TON Blockchain Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + TON Blockchain Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with TON Blockchain Library. If not, see . + + Copyright 2017-2020 Telegram Systems LLP +*/ +#pragma once + +#include "td/utils/common.h" +#include "Ed25519.h" +#include "block/block.h" +#include "vm/cells/CellString.h" + +#include "SmartContract.h" + +namespace ton { +class WalletInterface { + public: + struct Gift { + block::StdAddress destination; + td::int64 gramms; + + bool is_encrypted{false}; + std::string message; + + td::Ref body; + }; + + virtual ~WalletInterface() { + } + + virtual size_t get_max_gifts_size() const = 0; + virtual td::Result> make_a_gift_message(const td::Ed25519::PrivateKey &private_key, + td::uint32 valid_until, td::Span gifts) const = 0; + virtual td::Result get_public_key() const { + return td::Status::Error("TODO"); + } + + td::Result> get_init_message(const td::Ed25519::PrivateKey &private_key, + td::uint32 valid_until = std::numeric_limits::max()) { + return make_a_gift_message(private_key, valid_until, {}); + } + static void store_gift_message(vm::CellBuilder &cb, const Gift &gift) { + if (gift.body.not_null()) { + auto body = vm::load_cell_slice(gift.body); + //TODO: handle error + cb.append_cellslice_bool(body); + return; + } + + if (gift.is_encrypted) { + cb.store_long(1, 32); + } else { + cb.store_long(0, 32); + } + vm::CellString::store(cb, gift.message, 35 * 8).ensure(); + } +}; + +} // namespace ton diff --git a/submodules/ton/tonlib-src/crypto/smc-envelope/WalletV3.cpp b/submodules/ton/tonlib-src/crypto/smc-envelope/WalletV3.cpp index db39c725ef..39993c66e6 100644 --- a/submodules/ton/tonlib-src/crypto/smc-envelope/WalletV3.cpp +++ b/submodules/ton/tonlib-src/crypto/smc-envelope/WalletV3.cpp @@ -14,10 +14,11 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "WalletV3.h" #include "GenericAccount.h" +#include "SmartContractCode.h" #include "vm/boc.h" #include "vm/cells/CellString.h" @@ -26,76 +27,70 @@ #include namespace ton { -td::Ref WalletV3::get_init_state(const td::Ed25519::PublicKey& public_key, td::uint32 wallet_id) noexcept { - auto code = get_init_code(); +td::Ref WalletV3::get_init_state(const td::Ed25519::PublicKey& public_key, td::uint32 wallet_id, + td::int32 revision) noexcept { + auto code = get_init_code(revision); auto data = get_init_data(public_key, wallet_id); return GenericAccount::get_init_state(std::move(code), std::move(data)); } -td::Ref WalletV3::get_init_message(const td::Ed25519::PrivateKey& private_key, - td::uint32 wallet_id) noexcept { - td::uint32 seqno = 0; - td::uint32 valid_until = std::numeric_limits::max(); - auto signature = private_key - .sign(vm::CellBuilder() - .store_long(wallet_id, 32) - .store_long(valid_until, 32) - .store_long(seqno, 32) - .finalize() - ->get_hash() - .as_slice()) - .move_as_ok(); - return vm::CellBuilder() - .store_bytes(signature) - .store_long(wallet_id, 32) - .store_long(valid_until, 32) - .store_long(seqno, 32) - .finalize(); +td::optional WalletV3::guess_revision(const vm::Cell::Hash& code_hash) { + for (td::int32 i = 1; i <= 2; i++) { + if (get_init_code(i)->get_hash() == code_hash) { + return i; + } + } + return {}; +} +td::optional WalletV3::guess_revision(const block::StdAddress& address, + const td::Ed25519::PublicKey& public_key, td::uint32 wallet_id) { + for (td::int32 i = 1; i <= 2; i++) { + if (GenericAccount::get_address(address.workchain, get_init_state(public_key, wallet_id, i)) == address) { + return i; + } + } + return {}; } td::Ref WalletV3::make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 wallet_id, - td::uint32 seqno, td::uint32 valid_until, td::int64 gramms, - td::Slice message, const block::StdAddress& dest_address) noexcept { - td::int32 send_mode = 3; - if (gramms == -1) { - gramms = 0; - send_mode += 128; - } - vm::CellBuilder cb; - GenericAccount::store_int_message(cb, dest_address, gramms); - cb.store_bytes("\0\0\0\0", 4); - vm::CellString::store(cb, message, 35 * 8).ensure(); - auto message_inner = cb.finalize(); + td::uint32 seqno, td::uint32 valid_until, + td::Span gifts) noexcept { + CHECK(gifts.size() <= max_gifts_size); - auto message_outer = vm::CellBuilder() - .store_long(wallet_id, 32) - .store_long(valid_until, 32) - .store_long(seqno, 32) - .store_long(send_mode, 8) - .store_ref(message_inner) - .finalize(); + vm::CellBuilder cb; + cb.store_long(wallet_id, 32).store_long(valid_until, 32).store_long(seqno, 32); + + for (auto& gift : gifts) { + td::int32 send_mode = 3; + auto gramms = gift.gramms; + if (gramms == -1) { + gramms = 0; + send_mode += 128; + } + vm::CellBuilder cbi; + GenericAccount::store_int_message(cbi, gift.destination, gramms); + store_gift_message(cbi, gift); + auto message_inner = cbi.finalize(); + cb.store_long(send_mode, 8).store_ref(std::move(message_inner)); + } + + auto message_outer = cb.finalize(); auto signature = private_key.sign(message_outer->get_hash().as_slice()).move_as_ok(); return vm::CellBuilder().store_bytes(signature).append_cellslice(vm::load_cell_slice(message_outer)).finalize(); } -td::Ref WalletV3::get_init_code() noexcept { - static auto res = [] { - auto serialized_code = td::base64_decode( - "te6ccgEBAQEAYgAAwP8AIN0gggFMl7qXMO1E0NcLH+Ck8mCDCNcYINMf0x/TH/gjE7vyY+1E0NMf0x/T/" - "9FRMrryoVFEuvKiBPkBVBBV+RDyo/gAkyDXSpbTB9QC+wDo0QGkyMsfyx/L/8ntVA==") - .move_as_ok(); - return vm::std_boc_deserialize(serialized_code).move_as_ok(); - }(); - return res; +td::Ref WalletV3::get_init_code(td::int32 revision) noexcept { + return SmartContractCode::get_code(ton::SmartContractCode::WalletV3, revision); } vm::CellHash WalletV3::get_init_code_hash() noexcept { return get_init_code()->get_hash(); } -td::Ref WalletV3::get_init_data(const td::Ed25519::PublicKey& public_key, td::uint32 wallet_id) noexcept { +td::Ref WalletV3::get_init_data(const td::Ed25519::PublicKey& public_key, td::uint32 wallet_id, + td::uint32 seqno) noexcept { return vm::CellBuilder() - .store_long(0, 32) + .store_long(seqno, 32) .store_long(wallet_id, 32) .store_bytes(public_key.as_octet_string()) .finalize(); @@ -127,4 +122,20 @@ td::Result WalletV3::get_wallet_id_or_throw() const { return static_cast(cs.fetch_ulong(32)); } +td::Result WalletV3::get_public_key() const { + return TRY_VM(get_public_key_or_throw()); +} + +td::Result WalletV3::get_public_key_or_throw() const { + if (state_.data.is_null()) { + return td::Status::Error("data is null"); + } + //FIXME use get method + auto cs = vm::load_cell_slice(state_.data); + cs.skip_first(64); + td::SecureString res(td::Ed25519::PublicKey::LENGTH); + cs.fetch_bytes(res.as_mutable_slice().ubegin(), td::narrow_cast(res.size())); + return td::Ed25519::PublicKey(std::move(res)); +} + } // namespace ton diff --git a/submodules/ton/tonlib-src/crypto/smc-envelope/WalletV3.h b/submodules/ton/tonlib-src/crypto/smc-envelope/WalletV3.h index a6e4162df2..b7c211ca54 100644 --- a/submodules/ton/tonlib-src/crypto/smc-envelope/WalletV3.h +++ b/submodules/ton/tonlib-src/crypto/smc-envelope/WalletV3.h @@ -14,37 +14,59 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once #include "smc-envelope/SmartContract.h" +#include "smc-envelope/WalletInterface.h" #include "vm/cells.h" #include "Ed25519.h" #include "block/block.h" #include "vm/cells/CellString.h" namespace ton { -class WalletV3 : ton::SmartContract { +class WalletV3 : ton::SmartContract, public WalletInterface { public: explicit WalletV3(State state) : ton::SmartContract(std::move(state)) { } + explicit WalletV3(const td::Ed25519::PublicKey& public_key, td::uint32 wallet_id, td::uint32 seqno = 0) + : WalletV3(State{get_init_code(), get_init_data(public_key, wallet_id, seqno)}) { + } static constexpr unsigned max_message_size = vm::CellString::max_bytes; - static td::Ref get_init_state(const td::Ed25519::PublicKey& public_key, td::uint32 wallet_id) noexcept; - static td::Ref get_init_message(const td::Ed25519::PrivateKey& private_key, td::uint32 wallet_id) noexcept; - static td::Ref make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 wallet_id, - td::uint32 seqno, td::uint32 valid_until, td::int64 gramms, - td::Slice message, const block::StdAddress& dest_address) noexcept; + static constexpr unsigned max_gifts_size = 4; - static td::Ref get_init_code() noexcept; + static td::optional guess_revision(const vm::Cell::Hash& code_hash); + static td::optional guess_revision(const block::StdAddress& address, + const td::Ed25519::PublicKey& public_key, td::uint32 wallet_id); + static td::Ref get_init_state(const td::Ed25519::PublicKey& public_key, td::uint32 wallet_id, + td::int32 revision = 0) noexcept; + static td::Ref make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 wallet_id, + td::uint32 seqno, td::uint32 valid_until, td::Span gifts) noexcept; + + static td::Ref get_init_code(td::int32 revision = 0) noexcept; static vm::CellHash get_init_code_hash() noexcept; - static td::Ref get_init_data(const td::Ed25519::PublicKey& public_key, td::uint32 wallet_id) noexcept; + static td::Ref get_init_data(const td::Ed25519::PublicKey& public_key, td::uint32 wallet_id, + td::uint32 seqno = 0) noexcept; td::Result get_seqno() const; td::Result get_wallet_id() const; + using WalletInterface::get_init_message; + td::Result> make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 valid_until, + td::Span gifts) const override { + TRY_RESULT(seqno, get_seqno()); + TRY_RESULT(wallet_id, get_wallet_id()); + return make_a_gift_message(private_key, wallet_id, seqno, valid_until, gifts); + } + size_t get_max_gifts_size() const override { + return max_gifts_size; + } + td::Result get_public_key() const override; + private: td::Result get_seqno_or_throw() const; td::Result get_wallet_id_or_throw() const; + td::Result get_public_key_or_throw() const; }; } // namespace ton diff --git a/submodules/ton/tonlib-src/crypto/test/fift/testdict.fif b/submodules/ton/tonlib-src/crypto/test/fift/testdict.fif index 307bd2e805..28d711ade7 100644 --- a/submodules/ton/tonlib-src/crypto/test/fift/testdict.fif +++ b/submodules/ton/tonlib-src/crypto/test/fift/testdict.fif @@ -1,4 +1,4 @@ -"Lisp.fif" include +"Lists.fif" include 16 constant key-bits 16 constant val-bits { val-bits u, } : val, @@ -7,8 +7,14 @@ { dictnew { over null? not } { swap uncons swap rot +dictpair } while nip } : mkdict { dup null? { ."(null) " drop } { val@ . } cond } : .val { key-bits { swap . ."-> " .val ."; " true } dictforeach drop cr } : show-dict +{ key-bits { swap . ."-> " .val ."; " true } idictforeach drop cr } : show-idict +{ key-bits { swap . ."-> " .val ."; " true } dictforeachrev drop cr } : show-rev-dict +{ key-bits { swap . ."-> " .val ."; " true } idictforeachrev drop cr } : show-rev-idict { key-bits { rot . ."-> " swap .val .val ."; " true } dictdiff drop cr } : show-dict-diff { key-bits { val@ swap val@ + val, true } dictmerge } : dict-sum +{ key-bits { val@ 2* val, true } dictmap } : dict-twice +{ key-bits { val@ 2 /mod { 2drop false } { val, true } cond } dictmap } : dict-half +{ key-bits { val@ + val, true } dictmapext } : dict-add-x { null swap key-bits { val@ pair swap cons true } dictforeach drop } : dict>list-rev { dict>list-rev list-reverse } : dict>list ( _( 13 169 ) _( 17 289 ) _( 10 100 ) ) mkdict =: Dict @@ -22,3 +28,7 @@ Dict2 dict>list .l cr Dict2 " .val ."; " true } dictforeach drop cr } : show-dict +{ key-bits { swap . ."-> " .val ."; " true } idictforeach drop cr } : show-idict +{ key-bits { swap . ."-> " .val ."; " true } dictforeachrev drop cr } : show-rev-dict +{ key-bits { swap . ."-> " .val ."; " true } idictforeachrev drop cr } : show-rev-idict +{ key-bits { rot . ."-> " swap .val .val ."; " true } dictdiff drop cr } : show-dict-diff +{ key-bits { swap . ."-> " .val ."; " true } rot dictforeachfromx drop cr } : show-dict-from +{ key-bits { val@ swap val@ + val, true } dictmerge } : dict-sum +{ key-bits { val@ 2* val, true } dictmap } : dict-twice +{ key-bits { val@ 2 /mod { 2drop false } { val, true } cond } dictmap } : dict-half +{ key-bits { val@ + val, true } dictmapext } : dict-add-x +{ null swap key-bits { val@ pair swap cons true } dictforeach drop } : dict>list-rev +{ dict>list-rev list-reverse } : dict>list +( _( 13 169 ) _( 17 289 ) _( 10 100 ) ) mkdict =: Dict +_( 4 16 ) _( 9 81 ) Dict +dictpair +dictpair =: Dict1 +_( 4 20 ) _( 101 10201 ) Dict +dictpair +dictpair =: Dict2 +_( 65533 9 ) Dict2 +dictpair =: Dict3 +."Dict1 = " Dict1 show-idict +."Dict2 = " Dict2 show-idict +."Dict3 = " Dict3 show-idict +variable D +{ D ! } : D! +{ ."D = " D @ show-idict } : show-D +{ D @ 2 show-dict-from } : show-D-from +{ D @ 6 show-dict-from } : show-D-from+ +{ D @ 18 show-dict-from } : show-D-from-hint +{ D @ 22 show-dict-from } : show-D-from-hint+ +variable hint hint 0! +{ ."D[" dup ._ ."..] = " show-D-from } : test-from +{ ."D[" dup ._ ."+..] = " show-D-from+ } : test-from+ +{ hint @ ."(hint=" dup ._ .") D[" over ._ ."..] = " show-D-from-hint } : test-from-hint +{ hint @ ."(hint=" dup ._ .") D[" over ._ ."+..] = " show-D-from-hint+ } : test-from-hint+ +{ -16 { 2dup swap execute 1+ } 120 times 2drop } : range-run +{ hint ! ' test-from-hint range-run ' test-from-hint+ range-run } : range-test-hint + +{ ."------- BIG TEST -------" cr show-D + ' test-from range-run ' test-from+ range-run + 0 range-test-hint 13 range-test-hint 7 range-test-hint 100 range-test-hint +} : big-test +Dict1 D! +big-test +Dict2 D! +big-test +Dict3 D! +big-test diff --git a/submodules/ton/tonlib-src/crypto/test/test-db.cpp b/submodules/ton/tonlib-src/crypto/test/test-db.cpp index 148a185494..1b7e19009d 100644 --- a/submodules/ton/tonlib-src/crypto/test/test-db.cpp +++ b/submodules/ton/tonlib-src/crypto/test/test-db.cpp @@ -39,6 +39,7 @@ #include "td/utils/port/path.h" #include "td/utils/format.h" #include "td/utils/misc.h" +#include "td/utils/optional.h" #include "td/utils/tests.h" #include "td/utils/tl_parsers.h" #include "td/utils/tl_helpers.h" @@ -529,16 +530,20 @@ TEST(Cell, MerkleProofCombine) { ASSERT_EQ(exploration_b.log, exploration2.log); } - Ref proof_union; { - proof_union = MerkleProof::combine(proof1, proof2); + auto check = [&](auto proof_union) { + auto virtualized_proof = MerkleProof::virtualize(proof_union, 1); + auto exploration_a = CellExplorer::explore(virtualized_proof, exploration1.ops); + auto exploration_b = CellExplorer::explore(virtualized_proof, exploration2.ops); + ASSERT_EQ(exploration_a.log, exploration1.log); + ASSERT_EQ(exploration_b.log, exploration2.log); + }; + auto proof_union = MerkleProof::combine(proof1, proof2); ASSERT_EQ(proof_union->get_hash(), proof12->get_hash()); + check(proof_union); - auto virtualized_proof = MerkleProof::virtualize(proof_union, 1); - auto exploration_a = CellExplorer::explore(virtualized_proof, exploration1.ops); - auto exploration_b = CellExplorer::explore(virtualized_proof, exploration2.ops); - ASSERT_EQ(exploration_a.log, exploration1.log); - ASSERT_EQ(exploration_b.log, exploration2.log); + auto proof_union_fast = MerkleProof::combine_fast(proof1, proof2); + check(proof_union_fast); } { auto cell = MerkleProof::virtualize(proof12, 1); @@ -1194,6 +1199,88 @@ TEST(Cell, MerkleProofArrayHands) { test_boc_deserializer_full(proof).ensure(); test_boc_deserializer_full(CellBuilder::create_merkle_proof(proof)).ensure(); } + +TEST(Cell, MerkleProofCombineArray) { + size_t n = 1 << 15; + std::vector data; + for (size_t i = 0; i < n; i++) { + data.push_back(i / 3); + } + CompactArray arr(data); + + td::Ref root = vm::CellBuilder::create_merkle_proof(arr.merkle_proof({})); + td::Timer timer; + for (size_t i = 0; i < n; i++) { + auto new_root = vm::CellBuilder::create_merkle_proof(arr.merkle_proof({i})); + root = vm::MerkleProof::combine_fast(root, new_root); + if ((i - 1) % 100 == 0) { + LOG(ERROR) << timer; + timer = {}; + } + } + + CompactArray arr2(n, vm::MerkleProof::virtualize(root, 1)); + for (size_t i = 0; i < n; i++) { + CHECK(arr.get(i) == arr2.get(i)); + } +} + +TEST(Cell, MerkleProofCombineArray2) { + auto a = vm::CellBuilder().store_long(1, 8).finalize(); + auto b = vm::CellBuilder().store_long(2, 8).finalize(); + auto c = vm::CellBuilder().store_long(3, 8).finalize(); + auto d = vm::CellBuilder().store_long(4, 8).finalize(); + auto left = vm::CellBuilder().store_ref(a).store_ref(b).finalize(); + auto right = vm::CellBuilder().store_ref(c).store_ref(d).finalize(); + auto x = vm::CellBuilder().store_ref(left).store_ref(right).finalize(); + size_t n = 18; + //TODO: n = 100, currently TL + for (size_t i = 0; i < n; i++) { + x = vm::CellBuilder().store_ref(x).store_ref(x).finalize(); + } + + td::Ref root; + auto apply_op = [&](auto op) { + auto usage_tree = std::make_shared(); + auto usage_cell = UsageCell::create(x, usage_tree->root_ptr()); + root = usage_cell; + op(); + return MerkleProof::generate(root, usage_tree.get()); + }; + + auto first = apply_op([&] { + auto x = root; + while (true) { + auto cs = vm::load_cell_slice(x); + if (cs.size_refs() == 0) { + break; + } + x = cs.prefetch_ref(0); + } + }); + auto second = apply_op([&] { + auto x = root; + while (true) { + auto cs = vm::load_cell_slice(x); + if (cs.size_refs() == 0) { + break; + } + x = cs.prefetch_ref(1); + } + }); + + { + td::Timer t; + auto x = vm::MerkleProof::combine(first, second); + LOG(ERROR) << "slow " << t; + } + { + td::Timer t; + auto x = vm::MerkleProof::combine_fast(first, second); + LOG(ERROR) << "fast " << t; + } +} + TEST(Cell, MerkleUpdateHands) { auto data = CellBuilder{}.store_bytes("pruned data").store_ref(CellBuilder{}.finalize()).finalize(); auto node = CellBuilder{}.store_bytes("protected data").store_ref(data).finalize(); @@ -1965,6 +2052,222 @@ TEST(Ref, AtomicRef) { LOG(ERROR) << String::total_strings.sum(); } +class FileMerkleTree { + public: + FileMerkleTree(size_t chunks_count, td::Ref root = {}) { + log_n_ = 0; + while ((size_t(1) << log_n_) < chunks_count) { + log_n_++; + } + n_ = size_t(1) << log_n_; + mark_.resize(n_ * 2); + proof_.resize(n_ * 2); + + CHECK(n_ == chunks_count); // TODO: support other chunks_count + //auto x = vm::CellBuilder().finalize(); + root_ = std::move(root); + } + + struct Chunk { + td::size_t index{0}; + td::Slice hash; + }; + + void remove_chunk(td::size_t index) { + CHECK(index < n_); + index += n_; + while (proof_[index].not_null()) { + proof_[index] = {}; + index /= 2; + } + } + + bool has_chunk(td::size_t index) const { + CHECK(index < n_); + index += n_; + return proof_[index].not_null(); + } + + void add_chunk(td::size_t index, td::Slice hash) { + CHECK(hash.size() == 32); + CHECK(index < n_); + index += n_; + auto cell = vm::CellBuilder().store_bytes(hash).finalize(); + CHECK(proof_[index].is_null()); + proof_[index] = std::move(cell); + for (index /= 2; index != 0; index /= 2) { + CHECK(proof_[index].is_null()); + auto &left = proof_[index * 2]; + auto &right = proof_[index * 2 + 1]; + if (left.not_null() && right.not_null()) { + proof_[index] = vm::CellBuilder().store_ref(left).store_ref(right).finalize(); + } else { + mark_[index] = mark_id_; + } + } + } + + td::Status validate_proof(td::Ref new_root) { + // TODO: check structure + return td::Status::OK(); + } + + td::Status add_proof(td::Ref new_root) { + TRY_STATUS(validate_proof(new_root)); + auto combined = vm::MerkleProof::combine_fast_raw(root_, new_root); + if (combined.is_null()) { + return td::Status::Error("Can't combine proofs"); + } + root_ = std::move(combined); + return td::Status::OK(); + } + + td::Status try_add_chunks(td::Span chunks) { + for (auto chunk : chunks) { + if (has_chunk(chunk.index)) { + return td::Status::Error("Already has chunk"); + } + } + mark_id_++; + for (auto chunk : chunks) { + add_chunk(chunk.index, chunk.hash); + } + auto r_new_root = merge(root_, 1); + if (r_new_root.is_error()) { + for (auto chunk : chunks) { + remove_chunk(chunk.index); + } + return r_new_root.move_as_error(); + } + root_ = r_new_root.move_as_ok(); + return td::Status::OK(); + } + + td::Result> merge(td::Ref root, size_t index) { + const auto &down = proof_[index]; + if (down.not_null()) { + if (down->get_hash() != root->get_hash(0)) { + return td::Status::Error("Hash mismatch"); + } + return down; + } + + if (mark_[index] != mark_id_) { + return root; + } + + vm::CellSlice cs(vm::NoVm(), root); + if (cs.is_special()) { + return td::Status::Error("Proof is not enough to validate chunks"); + } + + CHECK(cs.size_refs() == 2); + vm::CellBuilder cb; + cb.store_bits(cs.fetch_bits(cs.size())); + TRY_RESULT(left, merge(cs.fetch_ref(), index * 2)); + TRY_RESULT(right, merge(cs.fetch_ref(), index * 2 + 1)); + cb.store_ref(std::move(left)).store_ref(std::move(right)); + return cb.finalize(); + } + + void init_proof() { + CHECK(proof_[1].not_null()); + root_ = proof_[1]; + } + + td::Result> gen_proof(size_t l, size_t r) { + auto usage_tree = std::make_shared(); + auto usage_cell = vm::UsageCell::create(root_, usage_tree->root_ptr()); + TRY_STATUS(do_gen_proof(std::move(usage_cell), 0, n_ - 1, l, r)); + auto res = vm::MerkleProof::generate_raw(root_, usage_tree.get()); + CHECK(res.not_null()); + return res; + } + + private: + td::size_t n_; // n = 2^log_n + td::size_t log_n_; + td::size_t mark_id_{0}; + std::vector mark_; // n_ * 2 + std::vector> proof_; // n_ * 2 + td::Ref root_; + + td::Status do_gen_proof(td::Ref node, size_t il, size_t ir, size_t l, size_t r) { + if (ir < l || il > r) { + return td::Status::OK(); + } + if (l <= il && ir <= r) { + return td::Status::OK(); + } + vm::CellSlice cs(vm::NoVm(), std::move(node)); + if (cs.is_special()) { + return td::Status::Error("Can't generate a proof"); + } + CHECK(cs.size_refs() == 2); + auto ic = (il + ir) / 2; + TRY_STATUS(do_gen_proof(cs.fetch_ref(), il, ic, l, r)); + TRY_STATUS(do_gen_proof(cs.fetch_ref(), ic + 1, ir, l, r)); + return td::Status::OK(); + } +}; + +TEST(FileMerkleTree, Manual) { + // create big random file + size_t chunk_size = 768; + // for simplicity numer of chunks in a file is a power of two + size_t chunks_count = 1 << 16; + size_t file_size = chunk_size * chunks_count; + td::Timer timer; + LOG(INFO) << "Generate random string"; + const auto file = td::rand_string('a', 'z', td::narrow_cast(file_size)); + LOG(INFO) << timer; + + timer = {}; + LOG(INFO) << "Calculate all hashes"; + std::vector hashes(chunks_count); + for (size_t i = 0; i < chunks_count; i++) { + td::sha256(td::Slice(file).substr(i * chunk_size, chunk_size), hashes[i].as_slice()); + } + LOG(INFO) << timer; + + timer = {}; + LOG(INFO) << "Init merkle tree"; + FileMerkleTree tree(chunks_count); + for (size_t i = 0; i < chunks_count; i++) { + tree.add_chunk(i, hashes[i].as_slice()); + } + tree.init_proof(); + LOG(INFO) << timer; + + auto root_proof = tree.gen_proof(0, chunks_count - 1).move_as_ok(); + + // first download each chunk one by one + + for (size_t stride : {1 << 6, 1}) { + timer = {}; + LOG(INFO) << "Gen all proofs, stride = " << stride; + for (size_t i = 0; i < chunks_count; i += stride) { + tree.gen_proof(i, i + stride - 1).move_as_ok(); + } + LOG(INFO) << timer; + timer = {}; + LOG(INFO) << "Proof size: " << vm::std_boc_serialize(tree.gen_proof(0, stride - 1).move_as_ok()).ok().size(); + LOG(INFO) << "Download file, stride = " << stride; + { + FileMerkleTree new_tree(chunks_count, root_proof); + for (size_t i = 0; i < chunks_count; i += stride) { + new_tree.add_proof(tree.gen_proof(i, i + stride - 1).move_as_ok()).ensure(); + std::vector chunks; + for (size_t j = 0; j < stride; j++) { + chunks.push_back({i + j, hashes[i + j].as_slice()}); + } + new_tree.try_add_chunks(chunks).ensure(); + } + } + LOG(INFO) << timer; + } +} + //TEST(Tmp, Boc) { //LOG(ERROR) << "A"; //auto data = td::read_file("boc"); diff --git a/submodules/ton/tonlib-src/crypto/test/test-smartcont.cpp b/submodules/ton/tonlib-src/crypto/test/test-smartcont.cpp index c0b991b620..eb6e88802f 100644 --- a/submodules/ton/tonlib-src/crypto/test/test-smartcont.cpp +++ b/submodules/ton/tonlib-src/crypto/test/test-smartcont.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "vm/dict.h" #include "common/bigint.hpp" @@ -28,6 +28,7 @@ #include "fift/utils.h" #include "smc-envelope/GenericAccount.h" +#include "smc-envelope/ManualDns.h" #include "smc-envelope/MultisigWallet.h" #include "smc-envelope/SmartContract.h" #include "smc-envelope/SmartContractCode.h" @@ -35,6 +36,8 @@ #include "smc-envelope/TestWallet.h" #include "smc-envelope/Wallet.h" #include "smc-envelope/WalletV3.h" +#include "smc-envelope/HighloadWallet.h" +#include "smc-envelope/HighloadWalletV2.h" #include "td/utils/base64.h" #include "td/utils/crypto.h" @@ -46,6 +49,7 @@ #include "td/utils/PathView.h" #include "td/utils/filesystem.h" #include "td/utils/port/path.h" +#include "td/utils/Variant.h" #include #include @@ -62,8 +66,8 @@ std::string load_source(std::string name) { td::Ref get_test_wallet_source() { std::string code = R"ABCD( SETCP0 DUP IFNOTRET // return if recv_internal -DUP 85143 INT EQUAL IFJMP:<{ // "seqno" get-method - DROP c4 PUSHCTR CTOS 32 PLDU // cnt +DUP 85143 INT EQUAL OVER 78748 INT EQUAL OR IFJMP:<{ // "seqno" and "get_public_key" get-methods + 1 INT AND c4 PUSHCTR CTOS 32 LDU 256 PLDU CONDSEL // cnt or pubk }> INC 32 THROWIF // fail unless recv_external 512 INT LDSLICEX DUP 32 PLDU // sign cs cnt @@ -90,8 +94,8 @@ INC NEWC 32 STU 256 STU ENDC c4 POPCTR td::Ref get_wallet_source() { std::string code = R"ABCD( SETCP0 DUP IFNOTRET // return if recv_internal - DUP 85143 INT EQUAL IFJMP:<{ // "seqno" get-method - DROP c4 PUSHCTR CTOS 32 PLDU // cnt + DUP 85143 INT EQUAL OVER 78748 INT EQUAL OR IFJMP:<{ // "seqno" and "get_public_key" get-methods + 1 INT AND c4 PUSHCTR CTOS 32 LDU 256 PLDU CONDSEL // cnt or pubk }> INC 32 THROWIF // fail unless recv_external 9 PUSHPOW2 LDSLICEX DUP 32 LDU 32 LDU // signature in_msg msg_seqno valid_until cs @@ -118,8 +122,8 @@ SETCP0 DUP IFNOTRET // return if recv_internal td::Ref get_wallet_v3_source() { std::string code = R"ABCD( SETCP0 DUP IFNOTRET // return if recv_internal - DUP 85143 INT EQUAL IFJMP:<{ // "seqno" get-method - DROP c4 PUSHCTR CTOS 32 PLDU // cnt + DUP 85143 INT EQUAL OVER 78748 INT EQUAL OR IFJMP:<{ // "seqno" and "get_public_key" get-methods + 1 INT AND c4 PUSHCTR CTOS 32 LDU 32 LDU NIP 256 PLDU CONDSEL // cnt or pubk }> INC 32 THROWIF // fail unless recv_external 9 PUSHPOW2 LDSLICEX DUP 32 LDU 32 LDU 32 LDU // signature in_msg subwallet_id valid_until msg_seqno cs @@ -175,8 +179,15 @@ TEST(Tonlib, TestWallet) { "321", "-C", "TEST"}) .move_as_ok(); auto wallet_query = fift_output.source_lookup.read_file("wallet-query.boc").move_as_ok().data; + ton::TestWallet::Gift gift; + gift.destination = dest; + gift.message = "TEST"; + gift.gramms = 321000000000ll; + ton::TestWallet wallet(priv_key.get_public_key().move_as_ok(), 123); + ASSERT_EQ(123u, wallet.get_seqno().ok()); + CHECK(priv_key.get_public_key().ok().as_octet_string() == wallet.get_public_key().ok().as_octet_string()); auto gift_message = ton::GenericAccount::create_ext_message( - address, {}, ton::TestWallet::make_a_gift_message(priv_key, 123, 321000000000ll, "TEST", dest)); + address, {}, wallet.make_a_gift_message(priv_key, 0, {gift}).move_as_ok()); LOG(ERROR) << "-------"; vm::load_cell_slice(gift_message).print_rec(std::cerr); LOG(ERROR) << "-------"; @@ -223,13 +234,20 @@ TEST(Tonlib, Wallet) { }; fift_output.source_lookup.set_os_time(std::make_unique()); auto dest = block::StdAddress::parse("Ef9Tj6fMJP+OqhAdhKXxq36DL+HYSzCc3+9O6UNzqsgPfYFX").move_as_ok(); - fift_output = - fift::mem_run_fift(std::move(fift_output.source_lookup), - {"aba", "new-wallet", "Ef9Tj6fMJP+OqhAdhKXxq36DL+HYSzCc3+9O6UNzqsgPfYFX", "123", "321"}) - .move_as_ok(); + fift_output = fift::mem_run_fift(std::move(fift_output.source_lookup), + {"aba", "new-wallet", "-C", "TESTv2", + "Ef9Tj6fMJP+OqhAdhKXxq36DL+HYSzCc3+9O6UNzqsgPfYFX", "123", "321"}) + .move_as_ok(); auto wallet_query = fift_output.source_lookup.read_file("wallet-query.boc").move_as_ok().data; + ton::TestWallet::Gift gift; + gift.destination = dest; + gift.message = "TESTv2"; + gift.gramms = 321000000000ll; + ton::Wallet wallet(priv_key.get_public_key().move_as_ok(), 123); + ASSERT_EQ(123u, wallet.get_seqno().ok()); + CHECK(priv_key.get_public_key().ok().as_octet_string() == wallet.get_public_key().ok().as_octet_string()); auto gift_message = ton::GenericAccount::create_ext_message( - address, {}, ton::Wallet::make_a_gift_message(priv_key, 123, 60, 321000000000ll, "TESTv2", dest)); + address, {}, wallet.make_a_gift_message(priv_key, 60, {gift}).move_as_ok()); LOG(ERROR) << "-------"; vm::load_cell_slice(gift_message).print_rec(std::cerr); LOG(ERROR) << "-------"; @@ -250,7 +268,8 @@ TEST(Tonlib, WalletV3) { td::Ed25519::PrivateKey priv_key{td::SecureString{new_wallet_pk}}; auto pub_key = priv_key.get_public_key().move_as_ok(); auto init_state = ton::WalletV3::get_init_state(pub_key, 239); - auto init_message = ton::WalletV3::get_init_message(priv_key, 239); + auto init_message = + ton::WalletV3(priv_key.get_public_key().move_as_ok(), 239).get_init_message(priv_key).move_as_ok(); auto address = ton::GenericAccount::get_address(0, init_state); CHECK(address.addr.as_slice() == td::Slice(new_wallet_addr).substr(0, 32)); @@ -272,13 +291,24 @@ TEST(Tonlib, WalletV3) { }; fift_output.source_lookup.set_os_time(std::make_unique()); auto dest = block::StdAddress::parse("Ef9Tj6fMJP+OqhAdhKXxq36DL+HYSzCc3+9O6UNzqsgPfYFX").move_as_ok(); - fift_output = - fift::mem_run_fift(std::move(fift_output.source_lookup), - {"aba", "new-wallet", "Ef9Tj6fMJP+OqhAdhKXxq36DL+HYSzCc3+9O6UNzqsgPfYFX", "239", "123", "321"}) - .move_as_ok(); + fift_output = fift::mem_run_fift(std::move(fift_output.source_lookup), + {"aba", "new-wallet", "-C", "TESTv3", + "Ef9Tj6fMJP+OqhAdhKXxq36DL+HYSzCc3+9O6UNzqsgPfYFX", "239", "123", "321"}) + .move_as_ok(); auto wallet_query = fift_output.source_lookup.read_file("wallet-query.boc").move_as_ok().data; + + ton::WalletV3::Gift gift; + gift.destination = dest; + gift.message = "TESTv3"; + gift.gramms = 321000000000ll; + + ton::WalletV3 wallet(priv_key.get_public_key().move_as_ok(), 239, 123); + ASSERT_EQ(239u, wallet.get_wallet_id().ok()); + ASSERT_EQ(123u, wallet.get_seqno().ok()); + CHECK(priv_key.get_public_key().ok().as_octet_string() == wallet.get_public_key().ok().as_octet_string()); + auto gift_message = ton::GenericAccount::create_ext_message( - address, {}, ton::WalletV3::make_a_gift_message(priv_key, 239, 123, 60, 321000000000ll, "TESTv3", dest)); + address, {}, wallet.make_a_gift_message(priv_key, 60, {gift}).move_as_ok()); LOG(ERROR) << "-------"; vm::load_cell_slice(gift_message).print_rec(std::cerr); LOG(ERROR) << "-------"; @@ -286,6 +316,152 @@ TEST(Tonlib, WalletV3) { CHECK(vm::std_boc_deserialize(wallet_query).move_as_ok()->get_hash() == gift_message->get_hash()); } +TEST(Tonlib, HighloadWallet) { + auto source_lookup = fift::create_mem_source_lookup(load_source("smartcont/new-highload-wallet.fif")).move_as_ok(); + source_lookup.write_file("/auto/highload-wallet-code.fif", load_source("smartcont/auto/highload-wallet-code.fif")) + .ensure(); + auto fift_output = fift::mem_run_fift(std::move(source_lookup), {"aba", "0", "239"}).move_as_ok(); + + LOG(ERROR) << fift_output.output; + auto new_wallet_pk = fift_output.source_lookup.read_file("new-wallet.pk").move_as_ok().data; + auto new_wallet_query = fift_output.source_lookup.read_file("new-wallet239-query.boc").move_as_ok().data; + auto new_wallet_addr = fift_output.source_lookup.read_file("new-wallet239.addr").move_as_ok().data; + + td::Ed25519::PrivateKey priv_key{td::SecureString{new_wallet_pk}}; + auto pub_key = priv_key.get_public_key().move_as_ok(); + auto init_state = ton::HighloadWallet::get_init_state(pub_key, 239); + auto init_message = ton::HighloadWallet::get_init_message(priv_key, 239); + auto address = ton::GenericAccount::get_address(0, init_state); + + ton::HighloadWallet wallet({ton::HighloadWallet::get_init_code(), ton::HighloadWallet::get_init_data(pub_key, 239)}); + ASSERT_EQ(239u, wallet.get_wallet_id().ok()); + ASSERT_EQ(0u, wallet.get_seqno().ok()); + CHECK(pub_key.as_octet_string() == wallet.get_public_key().ok().as_octet_string()); + + CHECK(address.addr.as_slice() == td::Slice(new_wallet_addr).substr(0, 32)); + + td::Ref res = ton::GenericAccount::create_ext_message(address, init_state, init_message); + + LOG(ERROR) << "---smc-envelope----"; + vm::load_cell_slice(res).print_rec(std::cerr); + LOG(ERROR) << "---fift scripts----"; + vm::load_cell_slice(vm::std_boc_deserialize(new_wallet_query).move_as_ok()).print_rec(std::cerr); + CHECK(vm::std_boc_deserialize(new_wallet_query).move_as_ok()->get_hash() == res->get_hash()); + + fift_output.source_lookup.write_file("/main.fif", load_source("smartcont/highload-wallet.fif")).ensure(); + std::string order; + std::vector gifts; + auto add_order = [&](td::Slice dest_str, td::int64 gramms) { + auto g = td::to_string(gramms); + if (g.size() < 10) { + g = std::string(10 - g.size(), '0') + g; + } + order += PSTRING() << "SEND " << dest_str << " " << g.substr(0, g.size() - 9) << "." << g.substr(g.size() - 9) + << "\n"; + + ton::HighloadWallet::Gift gift; + gift.destination = block::StdAddress::parse(dest_str).move_as_ok(); + gift.gramms = gramms; + gifts.push_back(gift); + }; + std::string dest_str = "Ef9Tj6fMJP+OqhAdhKXxq36DL+HYSzCc3+9O6UNzqsgPfYFX"; + add_order(dest_str, 0); + add_order(dest_str, 321000000000ll); + add_order(dest_str, 321ll); + fift_output.source_lookup.write_file("/order", order).ensure(); + class ZeroOsTime : public fift::OsTime { + public: + td::uint32 now() override { + return 0; + } + }; + fift_output.source_lookup.set_os_time(std::make_unique()); + fift_output = fift::mem_run_fift(std::move(fift_output.source_lookup), {"aba", "new-wallet", "239", "123", "order"}) + .move_as_ok(); + auto wallet_query = fift_output.source_lookup.read_file("wallet-query.boc").move_as_ok().data; + auto gift_message = ton::GenericAccount::create_ext_message( + address, {}, ton::HighloadWallet::make_a_gift_message(priv_key, 239, 123, 60, gifts)); + LOG(ERROR) << "---smc-envelope----"; + vm::load_cell_slice(gift_message).print_rec(std::cerr); + LOG(ERROR) << "---fift scripts----"; + vm::load_cell_slice(vm::std_boc_deserialize(wallet_query).move_as_ok()).print_rec(std::cerr); + CHECK(vm::std_boc_deserialize(wallet_query).move_as_ok()->get_hash() == gift_message->get_hash()); +} + +TEST(Tonlib, HighloadWalletV2) { + auto source_lookup = fift::create_mem_source_lookup(load_source("smartcont/new-highload-wallet-v2.fif")).move_as_ok(); + source_lookup + .write_file("/auto/highload-wallet-v2-code.fif", load_source("smartcont/auto/highload-wallet-v2-code.fif")) + .ensure(); + class ZeroOsTime : public fift::OsTime { + public: + td::uint32 now() override { + return 0; + } + }; + source_lookup.set_os_time(std::make_unique()); + auto fift_output = fift::mem_run_fift(std::move(source_lookup), {"aba", "0", "239"}).move_as_ok(); + + LOG(ERROR) << fift_output.output; + auto new_wallet_pk = fift_output.source_lookup.read_file("new-wallet.pk").move_as_ok().data; + auto new_wallet_query = fift_output.source_lookup.read_file("new-wallet239-query.boc").move_as_ok().data; + auto new_wallet_addr = fift_output.source_lookup.read_file("new-wallet239.addr").move_as_ok().data; + + td::Ed25519::PrivateKey priv_key{td::SecureString{new_wallet_pk}}; + auto pub_key = priv_key.get_public_key().move_as_ok(); + auto init_state = ton::HighloadWalletV2::get_init_state(pub_key, 239, -1); + auto init_message = ton::HighloadWalletV2::get_init_message(priv_key, 239, 65535); + auto address = ton::GenericAccount::get_address(0, init_state); + + ton::HighloadWalletV2 wallet( + {ton::HighloadWalletV2::get_init_code(-1), ton::HighloadWalletV2::get_init_data(pub_key, 239)}); + ASSERT_EQ(239u, wallet.get_wallet_id().ok()); + CHECK(pub_key.as_octet_string() == wallet.get_public_key().ok().as_octet_string()); + + CHECK(address.addr.as_slice() == td::Slice(new_wallet_addr).substr(0, 32)); + + td::Ref res = ton::GenericAccount::create_ext_message(address, init_state, init_message); + + LOG(ERROR) << "---smc-envelope----"; + vm::load_cell_slice(res).print_rec(std::cerr); + LOG(ERROR) << "---fift scripts----"; + vm::load_cell_slice(vm::std_boc_deserialize(new_wallet_query).move_as_ok()).print_rec(std::cerr); + CHECK(vm::std_boc_deserialize(new_wallet_query).move_as_ok()->get_hash() == res->get_hash()); + + fift_output.source_lookup.write_file("/main.fif", load_source("smartcont/highload-wallet-v2.fif")).ensure(); + std::string order; + std::vector gifts; + auto add_order = [&](td::Slice dest_str, td::int64 gramms) { + auto g = td::to_string(gramms); + if (g.size() < 10) { + g = std::string(10 - g.size(), '0') + g; + } + order += PSTRING() << "SEND " << dest_str << " " << g.substr(0, g.size() - 9) << "." << g.substr(g.size() - 9) + << "\n"; + + ton::HighloadWalletV2::Gift gift; + gift.destination = block::StdAddress::parse(dest_str).move_as_ok(); + gift.gramms = gramms; + gifts.push_back(gift); + }; + std::string dest_str = "Ef9Tj6fMJP+OqhAdhKXxq36DL+HYSzCc3+9O6UNzqsgPfYFX"; + add_order(dest_str, 0); + add_order(dest_str, 321000000000ll); + add_order(dest_str, 321ll); + fift_output.source_lookup.write_file("/order", order).ensure(); + fift_output.source_lookup.set_os_time(std::make_unique()); + fift_output = + fift::mem_run_fift(std::move(fift_output.source_lookup), {"aba", "new-wallet", "239", "order"}).move_as_ok(); + auto wallet_query = fift_output.source_lookup.read_file("wallet-query.boc").move_as_ok().data; + auto gift_message = ton::GenericAccount::create_ext_message( + address, {}, ton::HighloadWalletV2::make_a_gift_message(priv_key, 239, 60, gifts)); + LOG(ERROR) << "---smc-envelope----"; + vm::load_cell_slice(gift_message).print_rec(std::cerr); + LOG(ERROR) << "---fift scripts----"; + vm::load_cell_slice(vm::std_boc_deserialize(wallet_query).move_as_ok()).print_rec(std::cerr); + CHECK(vm::std_boc_deserialize(wallet_query).move_as_ok()->get_hash() == gift_message->get_hash()); +} + TEST(Tonlib, TestGiver) { auto address = block::StdAddress::parse("-1:60c04141c6a7b96d68615e7a91d265ad0f3a9a922e9ae9c901d4fa83f5d3c0d0").move_as_ok(); @@ -297,9 +473,13 @@ TEST(Tonlib, TestGiver) { auto wallet_query = fift_output.source_lookup.read_file("wallet-query.boc").move_as_ok().data; - auto res = ton::GenericAccount::create_ext_message( - ton::TestGiver::address(), {}, - ton::TestGiver::make_a_gift_message(0, 1000000000ll * 6666 / 1000, "GIFT", address)); + ton::TestGiver::Gift gift; + gift.gramms = 1000000000ll * 6666 / 1000; + gift.message = "GIFT"; + gift.destination = address; + td::Ed25519::PrivateKey key{td::SecureString()}; + auto res = ton::GenericAccount::create_ext_message(ton::TestGiver::address(), {}, + ton::TestGiver().make_a_gift_message(key, 0, {gift}).move_as_ok()); vm::CellSlice(vm::NoVm(), res).print_rec(std::cerr); CHECK(vm::std_boc_deserialize(wallet_query).move_as_ok()->get_hash() == res->get_hash()); } @@ -317,13 +497,16 @@ class SimpleWallet : public ton::SmartContract { } static td::Ref create_empty() { - return td::Ref(true, State{ton::SmartContractCode::simple_wallet_ext(), {}}); + return td::Ref(true, + State{ton::SmartContractCode::get_code(ton::SmartContractCode::WalletV1Ext), {}}); } static td::Ref create(td::Ref data) { - return td::Ref(true, State{ton::SmartContractCode::simple_wallet_ext(), std::move(data)}); + return td::Ref( + true, State{ton::SmartContractCode::get_code(ton::SmartContractCode::WalletV1Ext), std::move(data)}); } static td::Ref create_fast(td::Ref data) { - return td::Ref(true, State{ton::SmartContractCode::simple_wallet(), std::move(data)}); + return td::Ref( + true, State{ton::SmartContractCode::get_code(ton::SmartContractCode::WalletV1), std::move(data)}); } td::int32 seqno() const { @@ -387,16 +570,17 @@ TEST(Smartcon, Multisig) { int n = 100; int k = 99; + td::uint32 wallet_id = std::numeric_limits::max() - 3; std::vector keys; for (int i = 0; i < n; i++) { keys.push_back(td::Ed25519::generate_private_key().move_as_ok()); } auto init_state = ms_lib->create_init_data( - td::transform(keys, [](auto& key) { return key.get_public_key().ok().as_octet_string(); }), k); + wallet_id, td::transform(keys, [](auto& key) { return key.get_public_key().ok().as_octet_string(); }), k); auto ms = ton::MultisigWallet::create(init_state); - td::uint64 query_id = 123; - ton::MultisigWallet::QueryBuilder qb(query_id, vm::CellBuilder().finalize()); + td::uint64 query_id = 123 | ((100 * 60ull) << 32); + ton::MultisigWallet::QueryBuilder qb(wallet_id, query_id, vm::CellBuilder().finalize()); // first empty query (init) CHECK(ms.write().send_external_message(vm::CellBuilder().finalize()).code == 0); // first empty query @@ -423,7 +607,7 @@ TEST(Smartcon, Multisig) { ASSERT_EQ(0, ms->processed(query_id)); { - ton::MultisigWallet::QueryBuilder qb(query_id, vm::CellBuilder().finalize()); + ton::MultisigWallet::QueryBuilder qb(wallet_id, query_id, vm::CellBuilder().finalize()); for (int i = 50; i + 1 < 100; i++) { qb.sign(i, keys[i]); } @@ -439,6 +623,7 @@ TEST(Smartcon, Multisig) { TEST(Smartcont, MultisigStress) { int n = 10; int k = 5; + td::uint32 wallet_id = std::numeric_limits::max() - 3; std::vector keys; for (int i = 0; i < n; i++) { @@ -447,13 +632,14 @@ TEST(Smartcont, MultisigStress) { auto public_keys = td::transform(keys, [](auto& key) { return key.get_public_key().ok().as_octet_string(); }); auto ms_lib = ton::MultisigWallet::create(); auto init_state_old = - ms_lib->create_init_data_fast(td::transform(public_keys, [](auto& key) { return key.copy(); }), k); - auto init_state = ms_lib->create_init_data(td::transform(public_keys, [](auto& key) { return key.copy(); }), k); + ms_lib->create_init_data_fast(wallet_id, td::transform(public_keys, [](auto& key) { return key.copy(); }), k); + auto init_state = + ms_lib->create_init_data(wallet_id, td::transform(public_keys, [](auto& key) { return key.copy(); }), k); CHECK(init_state_old->get_hash() == init_state->get_hash()); auto ms = ton::MultisigWallet::create(init_state); CHECK(ms->get_public_keys() == public_keys); - td::int32 now = 0; + td::int32 now = 100 * 60; td::int32 qid = 1; using Mask = std::bitset<128>; struct Query { @@ -498,7 +684,7 @@ TEST(Smartcont, MultisigStress) { }; auto sign_query = [&](Query& query, Mask mask) { - auto qb = ton::MultisigWallet::QueryBuilder(query.id, query.message); + auto qb = ton::MultisigWallet::QueryBuilder(wallet_id, query.id, query.message); int first_i = -1; for (int i = 0; i < (int)mask.size(); i++) { if (mask.test(i)) { @@ -599,3 +785,457 @@ TEST(Smartcont, MultisigStress) { LOG(INFO) << "Final code size: " << ms->code_size(); LOG(INFO) << "Final data size: " << ms->data_size(); } + +class MapDns { + public: + using ManualDns = ton::ManualDns; + struct Entry { + std::string name; + td::int16 category{0}; + std::string text; + + auto key() const { + return std::tie(name, category); + } + bool operator<(const Entry& other) const { + return key() < other.key(); + } + bool operator==(const ton::DnsInterface::Entry& other) const { + return key() == other.key() && other.data.type == ManualDns::EntryData::Type::Text && + other.data.data.get().text == text; + } + bool operator==(const Entry& other) const { + return key() == other.key() && text == other.text; + } + friend td::StringBuilder& operator<<(td::StringBuilder& sb, const Entry& entry) { + return sb << "[" << entry.name << ":" << entry.category << ":" << entry.text << "]"; + } + }; + struct Action { + std::string name; + td::int16 category{0}; + td::optional text; + + bool does_create_category() const { + CHECK(!name.empty()); + CHECK(category != 0); + return static_cast(text); + } + bool does_change_empty() const { + CHECK(!name.empty()); + CHECK(category != 0); + return static_cast(text) && !text.value().empty(); + } + void make_non_empty() { + CHECK(!name.empty()); + CHECK(category != 0); + if (!text) { + text = ""; + } + } + friend td::StringBuilder& operator<<(td::StringBuilder& sb, const Action& entry) { + return sb << "[" << entry.name << ":" << entry.category << ":" << (entry.text ? entry.text.value() : "") + << "]"; + } + }; + void update(td::Span actions) { + for (auto& action : actions) { + do_update(action); + } + } + using CombinedActions = ton::ManualDns::CombinedActions; + void update_combined(td::Span actions) { + LOG(ERROR) << "BEGIN"; + LOG(ERROR) << td::format::as_array(actions); + auto combined_actions = ton::ManualDns::combine_actions(actions); + for (auto& c : combined_actions) { + LOG(ERROR) << c.name << ":" << c.category; + if (c.actions) { + LOG(ERROR) << td::format::as_array(c.actions.value()); + } + } + LOG(ERROR) << "END"; + for (auto& combined_action : combined_actions) { + do_update(combined_action); + } + } + + std::vector resolve(td::Slice name, td::int16 category) { + std::vector res; + if (name.empty()) { + for (auto& a : entries_) { + for (auto& b : a.second) { + res.push_back({a.first, b.first, b.second}); + } + } + } else { + auto it = entries_.find(name); + while (it == entries_.end()) { + auto sz = name.find('.'); + category = -1; + if (sz != td::Slice::npos) { + name = name.substr(sz + 1); + } else { + break; + } + it = entries_.find(name); + } + if (it != entries_.end()) { + for (auto& b : it->second) { + if (category == 0 || category == b.first) { + res.push_back({name.str(), b.first, b.second}); + } + } + } + } + + std::sort(res.begin(), res.end()); + return res; + } + + private: + std::map, std::less<>> entries_; + void do_update(const Action& action) { + if (action.name.empty()) { + entries_.clear(); + return; + } + if (action.category == 0) { + entries_.erase(action.name); + return; + } + if (action.text) { + if (action.text.value().empty()) { + entries_[action.name].erase(action.category); + } else { + entries_[action.name][action.category] = action.text.value(); + } + } else { + auto it = entries_.find(action.name); + if (it != entries_.end()) { + it->second.erase(action.category); + } + } + } + + void do_update(const CombinedActions& actions) { + if (actions.name.empty()) { + entries_.clear(); + LOG(ERROR) << "CLEAR"; + if (!actions.actions) { + return; + } + for (auto& action : actions.actions.value()) { + CHECK(!action.name.empty()); + CHECK(action.category != 0); + CHECK(action.text); + if (action.text.value().empty()) { + entries_[action.name]; + } else { + entries_[action.name][action.category] = action.text.value(); + } + } + return; + } + if (actions.category == 0) { + entries_.erase(actions.name); + LOG(ERROR) << "CLEAR " << actions.name; + if (!actions.actions) { + return; + } + entries_[actions.name]; + for (auto& action : actions.actions.value()) { + CHECK(action.name == actions.name); + CHECK(action.category != 0); + CHECK(action.text); + if (action.text.value().empty()) { + entries_[action.name]; + } else { + entries_[action.name][action.category] = action.text.value(); + } + } + return; + } + CHECK(actions.actions); + CHECK(actions.actions.value().size() == 1); + for (auto& action : actions.actions.value()) { + CHECK(action.name == actions.name); + CHECK(action.category != 0); + if (action.text) { + if (action.text.value().empty()) { + entries_[action.name].erase(action.category); + } else { + entries_[action.name][action.category] = action.text.value(); + } + } else { + auto it = entries_.find(action.name); + if (it != entries_.end()) { + it->second.erase(action.category); + } + } + } + } +}; + +class CheckedDns { + public: + explicit CheckedDns(bool check_smc = true, bool check_combine = true) { + if (check_smc) { + key_ = td::Ed25519::generate_private_key().move_as_ok(); + dns_ = ManualDns::create(ManualDns::create_init_data_fast(key_.value().get_public_key().move_as_ok(), 123)); + } + if (check_combine) { + combined_map_dns_ = MapDns(); + } + } + using Action = MapDns::Action; + using Entry = MapDns::Entry; + void update(td::Span entries) { + if (dns_.not_null()) { + auto smc_actions = td::transform(entries, [](auto& entry) { + ton::DnsInterface::Action action; + action.name = entry.name; + action.category = entry.category; + if (entry.text) { + if (entry.text.value().empty()) { + action.data = td::Ref(); + } else { + action.data = ManualDns::EntryData::text(entry.text.value()).as_cell().move_as_ok(); + } + } + return action; + }); + auto query = dns_->create_update_query(key_.value(), smc_actions).move_as_ok(); + CHECK(dns_.write().send_external_message(std::move(query)).code == 0); + } + map_dns_.update(entries); + if (combined_map_dns_) { + combined_map_dns_.value().update_combined(entries); + } + } + void update(const Action& action) { + return update(td::Span(&action, 1)); + } + + std::vector resolve(td::Slice name, td::int16 category) { + LOG(ERROR) << "RESOLVE: " << name << " " << category; + auto res = map_dns_.resolve(name, category); + LOG(ERROR) << td::format::as_array(res); + + if (dns_.not_null()) { + auto other_res = dns_->resolve(name, category).move_as_ok(); + + std::sort(other_res.begin(), other_res.end()); + if (res.size() != other_res.size()) { + LOG(ERROR) << td::format::as_array(res); + LOG(FATAL) << td::format::as_array(other_res); + } + for (size_t i = 0; i < res.size(); i++) { + if (!(res[i] == other_res[i])) { + LOG(ERROR) << td::format::as_array(res); + LOG(FATAL) << td::format::as_array(other_res); + } + } + } + if (combined_map_dns_) { + auto other_res = combined_map_dns_.value().resolve(name, category); + + std::sort(other_res.begin(), other_res.end()); + if (res.size() != other_res.size()) { + LOG(ERROR) << td::format::as_array(res); + LOG(FATAL) << td::format::as_array(other_res); + } + for (size_t i = 0; i < res.size(); i++) { + if (!(res[i] == other_res[i])) { + LOG(ERROR) << td::format::as_array(res); + LOG(FATAL) << td::format::as_array(other_res); + } + } + } + + return res; + } + + private: + using ManualDns = ton::ManualDns; + td::optional key_; + td::Ref dns_; + + MapDns map_dns_; + td::optional combined_map_dns_; + + void do_update_smc(const Action& entry) { + LOG(ERROR) << td::format::escaped(ManualDns::encode_name(entry.name)); + ton::DnsInterface::Action action; + action.name = entry.name; + action.category = entry.category; + action.data = ManualDns::EntryData::text(entry.text.value()).as_cell().move_as_ok(); + } +}; + +void do_dns_test(CheckedDns&& dns) { + using Action = CheckedDns::Action; + std::vector actions; + + td::Random::Xorshift128plus rnd(123); + + auto gen_name = [&] { + auto cnt = rnd.fast(1, 2); + std::string res; + for (int i = 0; i < cnt; i++) { + if (i != 0) { + res += '.'; + } + auto len = rnd.fast(1, 1); + for (int j = 0; j < len; j++) { + res += static_cast(rnd.fast('a', 'b')); + } + } + return res; + }; + auto gen_text = [&] { + std::string res; + int len = 5; + for (int j = 0; j < len; j++) { + res += static_cast(rnd.fast('a', 'b')); + } + return res; + }; + + auto gen_action = [&] { + Action action; + if (rnd.fast(0, 1000) == 0) { + return action; + } + action.name = gen_name(); + if (rnd.fast(0, 20) == 0) { + return action; + } + action.category = td::narrow_cast(rnd.fast(1, 5)); + if (rnd.fast(0, 4) == 0) { + return action; + } + if (rnd.fast(0, 4) == 0) { + action.text = ""; + return action; + } + action.text = gen_text(); + return action; + }; + + SET_VERBOSITY_LEVEL(VERBOSITY_NAME(ERROR)); + for (int i = 0; i < 100000; i++) { + actions.push_back(gen_action()); + if (rnd.fast(0, 10) == 0) { + dns.update(actions); + actions.clear(); + } + dns.resolve(gen_name(), td::narrow_cast(rnd.fast(0, 5))); + } +}; + +TEST(Smartcont, DnsManual) { + using ManualDns = ton::ManualDns; + auto test_entry_data = [](auto&& entry_data) { + auto cell = entry_data.as_cell().move_as_ok(); + auto cs = vm::load_cell_slice(cell); + auto new_entry_data = ManualDns::EntryData::from_cellslice(cs).move_as_ok(); + ASSERT_EQ(entry_data, new_entry_data); + }; + test_entry_data(ManualDns::EntryData::text("abcd")); + test_entry_data(ManualDns::EntryData::adnl_address(ton::Bits256{})); + + CHECK(td::Slice("a\0b\0") == ManualDns::encode_name("b.a")); + CHECK(td::Slice("a\0b\0") == ManualDns::encode_name(".b.a")); + ASSERT_EQ("b.a", ManualDns::decode_name("a\0b\0")); + ASSERT_EQ("b.a", ManualDns::decode_name("a\0b")); + ASSERT_EQ("", ManualDns::decode_name("")); + + auto key = td::Ed25519::generate_private_key().move_as_ok(); + + auto manual = ManualDns::create(ManualDns::create_init_data_fast(key.get_public_key().move_as_ok(), 123)); + CHECK(manual->get_wallet_id().move_as_ok() == 123); + auto init_query = manual->create_init_query(key).move_as_ok(); + LOG(ERROR) << "A"; + CHECK(manual.write().send_external_message(init_query).code == 0); + LOG(ERROR) << "B"; + CHECK(manual.write().send_external_message(init_query).code != 0); + + auto value = vm::CellBuilder().store_bytes("hello world").finalize(); + auto set_query = + manual + ->sign(key, + manual->prepare(manual->create_set_value_unsigned(1, "a\0b\0", value).move_as_ok(), 1).move_as_ok()) + .move_as_ok(); + CHECK(manual.write().send_external_message(set_query).code == 0); + + auto res = manual->run_get_method( + "dnsresolve", {vm::load_cell_slice_ref(vm::CellBuilder().store_bytes("a\0b\0").finalize()), td::make_refint(1)}); + CHECK(res.code == 0); + CHECK(res.stack.write().pop_cell()->get_hash() == value->get_hash()); + + CheckedDns dns; + dns.update(CheckedDns::Action{"a.b.c", 1, "hello"}); + CHECK(dns.resolve("a.b.c", 1).at(0).text == "hello"); + dns.resolve("a", 1); + dns.resolve("a.b", 1); + CHECK(dns.resolve("a.b.c", 2).empty()); + dns.update(CheckedDns::Action{"a.b.c", 2, "test"}); + CHECK(dns.resolve("a.b.c", 2).at(0).text == "test"); + dns.resolve("a.b.c", 1); + dns.resolve("a.b.c", 2); + LOG(ERROR) << "Test zero category"; + dns.resolve("a.b.c", 0); + dns.update(CheckedDns::Action{"", 0, ""}); + CHECK(dns.resolve("a.b.c", 2).empty()); + + LOG(ERROR) << "Test multipe update"; + { + CheckedDns::Action e[4] = {CheckedDns::Action{"", 0, ""}, CheckedDns::Action{"a.b.c", 1, "hello"}, + CheckedDns::Action{"a.b.c", 2, "world"}, CheckedDns::Action{"x.y.z", 3, "abc"}}; + dns.update(td::Span(e, 4)); + } + dns.resolve("a.b.c", 1); + dns.resolve("a.b.c", 2); + dns.resolve("x.y.z", 3); + + { + CheckedDns::Action e[1] = {CheckedDns::Action{"x.y.z", 0, ""}}; + dns.update(td::Span(e, 1)); + } + + dns.resolve("a.b.c", 1); + dns.resolve("a.b.c", 2); + dns.resolve("x.y.z", 3); + + { + CheckedDns::Action e[3] = {CheckedDns::Action{"x.y.z", 0, ""}, CheckedDns::Action{"x.y.z", 1, "xxx"}, + CheckedDns::Action{"x.y.z", 2, "yyy"}}; + dns.update(td::Span(e, 3)); + } + dns.resolve("a.b.c", 1); + dns.resolve("a.b.c", 2); + dns.resolve("x.y.z", 1); + dns.resolve("x.y.z", 2); + dns.resolve("x.y.z", 3); + + { + auto actions_ext = + ton::ManualDns::parse("delete.name one\nset one 1 TEXT:one\ndelete.name two\nset two 2 TEXT:two").move_as_ok(); + + auto actions = td::transform(actions_ext, [](auto& action) { + td::optional data; + if (action.data) { + data = action.data.value().data.template get().text; + } + return CheckedDns::Action{action.name, action.category, std::move(data)}; + }); + + dns.update(actions); + } + dns.resolve("one", 1); + dns.resolve("two", 2); + + // TODO: rethink semantic of creating an empty dictionary + do_dns_test(CheckedDns(true, true)); +} diff --git a/submodules/ton/tonlib-src/crypto/test/vm.cpp b/submodules/ton/tonlib-src/crypto/test/vm.cpp index 72e2f8c61b..77157f6d84 100644 --- a/submodules/ton/tonlib-src/crypto/test/vm.cpp +++ b/submodules/ton/tonlib-src/crypto/test/vm.cpp @@ -14,9 +14,9 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ -#include "vm/continuation.h" +#include "vm/vm.h" #include "vm/cp0.h" #include "vm/dict.h" #include "fift/utils.h" diff --git a/submodules/ton/tonlib-src/crypto/tl/tlbc-gen-cpp.cpp b/submodules/ton/tonlib-src/crypto/tl/tlbc-gen-cpp.cpp index bbf3adf79c..dedec15d49 100644 --- a/submodules/ton/tonlib-src/crypto/tl/tlbc-gen-cpp.cpp +++ b/submodules/ton/tonlib-src/crypto/tl/tlbc-gen-cpp.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "tlbc-gen-cpp.h" #include "td/utils/bits.h" @@ -94,6 +94,7 @@ void init_forbidden_cpp_idents() { l.insert("get_size"); l.insert("pack"); l.insert("unpack"); + l.insert("ops"); l.insert("cs"); l.insert("cb"); l.insert("cell_ref"); @@ -922,7 +923,7 @@ void CppTypeCode::generate_get_tag_param1(std::ostream& os, std::string nl, cons match_param_pattern(os, nl, A, 8, "# > 1 && (# & 1)", param_names[0])) { return; } - os << nl << "static inline size_t nat_abs(int x) { return (x > 1) * 2 + (x & 1); }"; + os << nl << "// static inline size_t nat_abs(int x) { return (x > 1) * 2 + (x & 1); }"; os << nl << "static signed char ctab[4] = { "; for (int i = 0; i < 4; i++) { if (i > 0) { @@ -941,7 +942,7 @@ void CppTypeCode::generate_get_tag_param2(std::ostream& os, std::string nl, cons os << ' ' << (int)A[i][j]; } } - os << nl << "static inline size_t nat_abs(int x) { return (x > 1) * 2 + (x & 1); }"; + os << nl << "// static inline size_t nat_abs(int x) { return (x > 1) * 2 + (x & 1); }"; os << nl << "static signed char ctab[4][4] = { "; for (int i = 0; i < 16; i++) { if (i > 0) { @@ -964,7 +965,7 @@ void CppTypeCode::generate_get_tag_param3(std::ostream& os, std::string nl, cons } } } - os << nl << "static inline size_t nat_abs(int x) { return (x > 1) * 2 + (x & 1); }"; + os << nl << "// static inline size_t nat_abs(int x) { return (x > 1) * 2 + (x & 1); }"; os << nl << "static signed char ctab[4][4][4] = { "; for (int i = 0; i < 64; i++) { if (i > 0) { @@ -2014,7 +2015,7 @@ void CppTypeCode::generate_skip_field(const Constructor& constr, const Field& fi output_cpp_expr(ss, expr, 100, true); ss << '.'; } - ss << (validating ? "validate_skip(cs, weak" : "skip(cs"); + ss << (validating ? "validate_skip(ops, cs, weak" : "skip(cs"); output_negative_type_arguments(ss, expr); ss << ")"; actions += Action{std::move(ss)}; @@ -2054,7 +2055,7 @@ void CppTypeCode::generate_skip_field(const Constructor& constr, const Field& fi output_cpp_expr(ss, expr, 100); ss << '.'; } - ss << (validating ? "validate_skip(cs, weak)" : "skip(cs)") << tail; + ss << (validating ? "validate_skip(ops, cs, weak)" : "skip(cs)") << tail; actions += Action{std::move(ss)}; return; } @@ -2074,7 +2075,7 @@ void CppTypeCode::generate_skip_field(const Constructor& constr, const Field& fi output_cpp_expr(ss, expr, 100); ss << '.'; } - ss << "validate_skip_ref(cs, weak)" << tail; + ss << "validate_skip_ref(ops, cs, weak)" << tail; actions += Action{ss.str()}; } @@ -2101,8 +2102,8 @@ void CppTypeCode::generate_skip_cons_method(std::ostream& os, std::string nl, in void CppTypeCode::generate_skip_method(std::ostream& os, int options) { bool validate = options & 1; bool ret_ext = options & 2; - os << "\nbool " << cpp_type_class_name << "::" << (validate ? "validate_" : "") << "skip(vm::CellSlice& cs" - << (validate ? ", bool weak" : ""); + os << "\nbool " << cpp_type_class_name + << "::" << (validate ? "validate_skip(int* ops, vm::CellSlice& cs, bool weak" : "skip(vm::CellSlice& cs"); if (ret_ext) { os << skip_extra_args; } @@ -2470,7 +2471,7 @@ void CppTypeCode::generate_unpack_field(const CppTypeCode::ConsField& fi, const output_cpp_expr(ss, expr, 100, true); ss << '.'; } - ss << (validating ? "validate_fetch_to(cs, weak, " : "fetch_to(cs, ") << field_vars.at(i); + ss << (validating ? "validate_fetch_to(ops, cs, weak, " : "fetch_to(cs, ") << field_vars.at(i); output_negative_type_arguments(ss, expr); ss << ")"; actions += Action{std::move(ss)}; @@ -2514,8 +2515,8 @@ void CppTypeCode::generate_unpack_field(const CppTypeCode::ConsField& fi, const output_cpp_expr(ss, expr, 100); ss << '.'; } - ss << (validating ? "validate_" : "") << "fetch_" << (cvt == ct_enum ? "enum_" : "") << "to(cs, " - << (validating ? "weak, " : "") << field_vars.at(i) << ")" << tail; + ss << (validating ? "validate_" : "") << "fetch_" << (cvt == ct_enum ? "enum_" : "") + << (validating ? "to(ops, cs, weak, " : "to(cs, ") << field_vars.at(i) << ")" << tail; field_var_set[i] = true; actions += Action{std::move(ss)}; return; @@ -2540,7 +2541,7 @@ void CppTypeCode::generate_unpack_field(const CppTypeCode::ConsField& fi, const output_cpp_expr(ss, expr, 100); ss << '.'; } - ss << "validate_ref(" << field_vars.at(i) << "))" << tail; + ss << "validate_ref(ops, " << field_vars.at(i) << "))" << tail; actions += Action{ss.str()}; } @@ -2559,7 +2560,11 @@ void CppTypeCode::generate_unpack_method(std::ostream& os, CppTypeCode::ConsReco << "\n auto cs = load_cell_slice(std::move(cell_ref));" << "\n return " << (options & 1 ? "validate_" : "") << "unpack"; if (!(options & 8)) { - os << "(cs, data"; + os << "("; + if (options & 1) { + os << "ops, "; + } + os << "cs, data"; } else { os << "_" << cons_enum_name.at(rec.cons_idx) << "(cs"; for (const auto& f : rec.cpp_fields) { @@ -2773,7 +2778,7 @@ void CppTypeCode::generate_pack_field(const CppTypeCode::ConsField& fi, const Co output_cpp_expr(ss, expr, 100); ss << '.'; } - ss << "validate_ref(" << field_vars.at(i) << "))" << tail; + ss << "validate_ref(ops, " << field_vars.at(i) << "))" << tail; actions += Action{ss.str()}; } @@ -3093,7 +3098,7 @@ void CppTypeCode::generate_header(std::ostream& os, int options) { if (ret_params) { os << " bool skip(vm::CellSlice& cs" << skip_extra_args << ") const;\n"; } - os << " bool validate_skip(vm::CellSlice& cs, bool weak = false) const override"; + os << " bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override"; if (!inline_validate_skip) { os << ";\n"; } else if (sz) { @@ -3102,7 +3107,7 @@ void CppTypeCode::generate_header(std::ostream& os, int options) { os << " {\n return true;\n }\n"; } if (ret_params) { - os << " bool validate_skip(vm::CellSlice& cs, bool weak" << skip_extra_args << ") const;\n"; + os << " bool validate_skip(int *ops, vm::CellSlice& cs, bool weak" << skip_extra_args << ") const;\n"; os << " bool fetch_to(vm::CellSlice& cs, Ref& res" << skip_extra_args << ") const;\n"; } if (type.is_simple_enum) { @@ -3257,6 +3262,31 @@ void generate_type_constants(std::ostream& os, int mode) { } } +void generate_register_function(std::ostream& os, int mode) { + os << "\n// " << (mode ? "definition" : "declaration") << " of type name registration function\n"; + if (!mode) { + os << "extern bool register_simple_types(std::function func);\n"; + return; + } + os << "bool register_simple_types(std::function func) {\n"; + os << " return "; + int k = 0; + for (int i = builtin_types_num; i < types_num; i++) { + Type& type = types[i]; + CppTypeCode& cc = *cpp_type[i]; + if (!cc.cpp_type_var_name.empty() && type.type_name) { + if (k++) { + os << "\n && "; + } + os << "func(\"" << type.get_name() << "\", &" << cc.cpp_type_var_name << ")"; + } + } + if (!k) { + os << "true"; + } + os << ";\n}\n\n"; +} + void assign_const_type_cpp_idents() { const_type_expr_cpp_idents.resize(const_type_expr_num + 1, ""); const_type_expr_simple.resize(const_type_expr_num + 1, false); @@ -3389,6 +3419,7 @@ void generate_cpp_output_to(std::ostream& os, int options = 0, std::vector= '0' && c <= '9') { c -= '0'; + } else if (c >= 'A' && c <= 'F') { + c -= 'A' - 10; } else if (c >= 'a' && c <= 'f') { c -= 'a' - 10; } else { @@ -146,6 +148,9 @@ unsigned long long get_special_value(std::string str) { while (bits && !((val >> (64 - bits)) & 1)) { --bits; } + if (bits) { + --bits; + } } if (bits == 64) { return 0; diff --git a/submodules/ton/tonlib-src/crypto/tl/tlblib.cpp b/submodules/ton/tonlib-src/crypto/tl/tlblib.cpp index 40637c57b4..617c298bb0 100644 --- a/submodules/ton/tonlib-src/crypto/tl/tlblib.cpp +++ b/submodules/ton/tonlib-src/crypto/tl/tlblib.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include @@ -33,6 +33,12 @@ const NatWidth t_Nat{32}; const Anything t_Anything; const RefAnything t_RefCell; +std::string TLB::get_type_name() const { + std::ostringstream os; + print_type(os); + return os.str(); +} + bool Bool::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const { int t = get_tag(cs); return cs.advance(1) && pp.out(t ? "bool_true" : "bool_false"); @@ -108,46 +114,52 @@ bool TupleT::skip(vm::CellSlice& cs) const { return !i; } -bool TupleT::validate_skip(vm::CellSlice& cs, bool weak) const { +bool TupleT::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { int i = n; for (; i > 0; --i) { - if (!X.validate_skip(cs, weak)) { + if (!X.validate_skip(ops, cs, weak)) { break; } } return !i; } -bool TLB::validate_ref_internal(Ref cell_ref, bool weak) const { +bool TLB::validate_ref_internal(int* ops, Ref cell_ref, bool weak) const { + if (ops && --*ops < 0) { + return false; + } bool is_special; auto cs = load_cell_slice_special(std::move(cell_ref), is_special); - return always_special() ? is_special : (is_special ? weak : (validate_skip(cs) && cs.empty_ext())); + return always_special() ? is_special : (is_special ? weak : (validate_skip(ops, cs) && cs.empty_ext())); } bool TLB::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const { pp.open("raw@"); pp << *this << ' '; vm::CellSlice cs_copy{cs}; - if (!validate_skip(cs) || !cs_copy.cut_tail(cs)) { + int size_limit = pp.limit; + if (!validate_skip(&size_limit, cs) || !cs_copy.cut_tail(cs)) { return pp.fail("invalid value"); } pp.raw_nl(); - cs_copy.print_rec(pp.os, pp.indent); - return pp.mkindent() && pp.close(); + return (cs_copy.print_rec(pp.os, &pp.limit, pp.indent) && pp.mkindent() && pp.close()) || + pp.fail("raw value too long"); } bool TLB::print_special(PrettyPrinter& pp, vm::CellSlice& cs) const { pp.open("raw@"); pp << *this << ' '; pp.raw_nl(); - cs.print_rec(pp.os, pp.indent); - return pp.mkindent() && pp.close(); + return (cs.print_rec(pp.os, &pp.limit, pp.indent) && pp.mkindent() && pp.close()) || pp.fail("raw value too long"); } bool TLB::print_ref(PrettyPrinter& pp, Ref cell_ref) const { if (cell_ref.is_null()) { return pp.fail("null cell reference"); } + if (!pp.register_recursive_call()) { + return pp.fail("too many recursive calls while printing a TL-B value"); + } bool is_special; auto cs = load_cell_slice_special(std::move(cell_ref), is_special); if (is_special) { @@ -157,18 +169,21 @@ bool TLB::print_ref(PrettyPrinter& pp, Ref cell_ref) const { } } -bool TLB::print_skip(std::ostream& os, vm::CellSlice& cs, int indent) const { +bool TLB::print_skip(std::ostream& os, vm::CellSlice& cs, int indent, int rec_limit) const { PrettyPrinter pp{os, indent}; + pp.set_limit(rec_limit); return pp.fail_unless(print_skip(pp, cs)); } -bool TLB::print(std::ostream& os, const vm::CellSlice& cs, int indent) const { +bool TLB::print(std::ostream& os, const vm::CellSlice& cs, int indent, int rec_limit) const { PrettyPrinter pp{os, indent}; + pp.set_limit(rec_limit); return pp.fail_unless(print(pp, cs)); } -bool TLB::print_ref(std::ostream& os, Ref cell_ref, int indent) const { +bool TLB::print_ref(std::ostream& os, Ref cell_ref, int indent, int rec_limit) const { PrettyPrinter pp{os, indent}; + pp.set_limit(rec_limit); return pp.fail_unless(print_ref(pp, std::move(cell_ref))); } @@ -207,7 +222,7 @@ PrettyPrinter::~PrettyPrinter() { } bool PrettyPrinter::fail(std::string msg) { - os << ""; + os << "" << std::endl; failed = true; return false; } @@ -340,3 +355,24 @@ bool PrettyPrinter::fetch_uint256_field(vm::CellSlice& cs, int n, std::string na } } // namespace tlb + +namespace tlb { + +bool TypenameLookup::register_types(typename TypenameLookup::register_func_t func) { + return func([this](const char* name, const TLB* tp) { return register_type(name, tp); }); +} + +bool TypenameLookup::register_type(const char* name, const TLB* tp) { + if (!name || !tp) { + return false; + } + auto res = types.emplace(name, tp); + return res.second; +} + +const TLB* TypenameLookup::lookup(std::string str) const { + auto it = types.find(str); + return it != types.end() ? it->second : nullptr; +} + +} // namespace tlb diff --git a/submodules/ton/tonlib-src/crypto/tl/tlblib.hpp b/submodules/ton/tonlib-src/crypto/tl/tlblib.hpp index b5d51c3154..7543d38f19 100644 --- a/submodules/ton/tonlib-src/crypto/tl/tlblib.hpp +++ b/submodules/ton/tonlib-src/crypto/tl/tlblib.hpp @@ -14,10 +14,11 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once #include +#include #include "vm/cellslice.h" namespace tlb { @@ -29,6 +30,7 @@ struct PrettyPrinter; class TLB { public: + enum { default_validate_max_cells = 1024 }; virtual ~TLB() = default; virtual int get_size(const vm::CellSlice& cs) const { return -1; @@ -36,14 +38,26 @@ class TLB { virtual bool skip(vm::CellSlice& cs) const { return cs.skip_ext(get_size(cs)); } - virtual bool validate(const vm::CellSlice& cs, bool weak = false) const { + virtual bool validate(int* ops, const vm::CellSlice& cs, bool weak = false) const { return cs.have_ext(get_size(cs)); } - virtual bool validate_exact(const vm::CellSlice& cs, bool weak = false) const { + virtual bool validate_exact(int* ops, const vm::CellSlice& cs, bool weak = false) const { return (int)cs.size_ext() == get_size(cs); } + bool validate_upto(int ops, const vm::CellSlice& cs, bool weak = false) const { + return validate(&ops, cs, weak); + } + bool validate_exact_upto(int ops, const vm::CellSlice& cs, bool weak = false) const { + return validate_exact(&ops, cs, weak); + } + bool validate_csr(int* ops, Ref cs_ref, bool weak = false) const { + return cs_ref.not_null() && validate_skip_exact(ops, cs_ref.write(), weak); + } + bool validate_csr(int ops, Ref cs_ref, bool weak = false) const { + return validate_csr(&ops, std::move(cs_ref), weak); + } bool validate_csr(Ref cs_ref, bool weak = false) const { - return cs_ref.not_null() && validate_skip_exact(cs_ref.write(), weak); + return validate_csr(default_validate_max_cells, std::move(cs_ref), weak); } Ref fetch(vm::CellSlice& cs) const { return cs.fetch_subslice_ext(get_size(cs)); @@ -51,67 +65,71 @@ class TLB { Ref prefetch(const vm::CellSlice& cs) const { return cs.prefetch_subslice_ext(get_size(cs)); } - virtual Ref validate_fetch(vm::CellSlice& cs, bool weak = false) const { - return validate(cs, weak) ? cs.fetch_subslice_ext(get_size(cs)) : Ref{}; + virtual Ref validate_fetch(int* ops, vm::CellSlice& cs, bool weak = false) const { + return validate(ops, cs, weak) ? cs.fetch_subslice_ext(get_size(cs)) : Ref{}; } - virtual Ref validate_prefetch(const vm::CellSlice& cs, bool weak = false) const { - return validate(cs, weak) ? cs.prefetch_subslice_ext(get_size(cs)) : Ref{}; + virtual Ref validate_prefetch(int* ops, const vm::CellSlice& cs, bool weak = false) const { + return validate(ops, cs, weak) ? cs.prefetch_subslice_ext(get_size(cs)) : Ref{}; } bool fetch_to(vm::CellSlice& cs, Ref& res) const { return (res = fetch(cs)).not_null(); } - bool validate_fetch_to(vm::CellSlice& cs, Ref& res, bool weak = false) const { - return (res = validate_fetch(cs, weak)).not_null(); + bool validate_fetch_to(int* ops, vm::CellSlice& cs, Ref& res, bool weak = false) const { + return (res = validate_fetch(ops, cs, weak)).not_null(); } bool store_from(vm::CellBuilder& cb, Ref field) const { return field.not_null() && get_size(*field) == (int)field->size_ext() && cb.append_cellslice_bool(std::move(field)); } - bool validate_store_from(vm::CellBuilder& cb, Ref field, bool weak = false) const { + bool validate_store_from(int* ops, vm::CellBuilder& cb, Ref field, bool weak = false) const { if (field.is_null()) { return false; } vm::CellSlice cs{*field}; - return validate_skip(cs, weak) && cs.empty_ext() && cb.append_cellslice_bool(std::move(field)); + return validate_skip(ops, cs, weak) && cs.empty_ext() && cb.append_cellslice_bool(std::move(field)); } virtual bool extract(vm::CellSlice& cs) const { return cs.only_ext(get_size(cs)); } - virtual bool validate_extract(vm::CellSlice& cs, bool weak = false) const { - return validate(cs, weak) && extract(cs); + virtual bool validate_extract(int* ops, vm::CellSlice& cs, bool weak = false) const { + return validate(ops, cs, weak) && extract(cs); } int get_size_by_skip(const vm::CellSlice& cs) const { vm::CellSlice copy{cs}; return skip(copy) ? copy.subtract_base_ext(cs) : -1; } - virtual bool validate_skip(vm::CellSlice& cs, bool weak = false) const { - return validate(cs, weak) && skip(cs); + virtual bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const { + return validate(ops, cs, weak) && skip(cs); } - bool validate_skip_exact(vm::CellSlice& cs, bool weak = false) const { - return validate_skip(cs, weak) && cs.empty_ext(); + bool validate_skip_upto(int ops, vm::CellSlice& cs, bool weak = false) const { + return validate_skip(&ops, cs, weak); } - bool validate_by_skip(const vm::CellSlice& cs, bool weak = false) const { + bool validate_skip_exact(int* ops, vm::CellSlice& cs, bool weak = false) const { + return validate_skip(ops, cs, weak) && cs.empty_ext(); + } + bool validate_by_skip(int* ops, const vm::CellSlice& cs, bool weak = false) const { vm::CellSlice copy{cs}; - return validate_skip(copy, weak); + return validate_skip(ops, copy, weak); } - bool validate_by_skip_exact(const vm::CellSlice& cs, bool weak = false) const { + bool validate_by_skip_exact(int* ops, const vm::CellSlice& cs, bool weak = false) const { vm::CellSlice copy{cs}; - return validate_skip_exact(copy, weak); + return validate_skip_exact(ops, copy, weak); } bool extract_by_skip(vm::CellSlice& cs) const { vm::CellSlice copy{cs}; return skip(copy) && cs.cut_tail(copy); } - bool validate_extract_by_skip(vm::CellSlice& cs, bool weak = false) const { + bool validate_extract_by_skip(int* ops, vm::CellSlice& cs, bool weak = false) const { vm::CellSlice copy{cs}; - return validate_skip(copy, weak) && cs.cut_tail(copy); + return validate_skip(ops, copy, weak) && cs.cut_tail(copy); } - Ref validate_fetch_by_skip(vm::CellSlice& cs, bool weak = false) const { + Ref validate_fetch_by_skip(int* ops, vm::CellSlice& cs, bool weak = false) const { Ref copy{true, cs}; - return validate_skip(cs, weak) && copy.unique_write().cut_tail(cs) ? copy : Ref{}; + return validate_skip(ops, cs, weak) && copy.unique_write().cut_tail(cs) ? copy : Ref{}; } - Ref validate_prefetch_by_skip(const vm::CellSlice& cs, bool weak = false) const { + Ref validate_prefetch_by_skip(int* ops, const vm::CellSlice& cs, bool weak = false) const { vm::CellSlice copy{cs}; - return validate_skip(copy, false) ? cs.prefetch_subslice_ext(copy.subtract_base_ext(cs)) : Ref{}; + return validate_skip(ops, copy, false) ? cs.prefetch_subslice_ext(copy.subtract_base_ext(cs)) + : Ref{}; } virtual bool skip_copy(vm::CellBuilder& cb, vm::CellSlice& cs) const { return cb.append_cellslice_bool(fetch(cs)); @@ -155,14 +173,29 @@ class TLB { bool as_integer_to(Ref cs_ref, td::RefInt256& res) const { return (res = as_integer(std::move(cs_ref))).not_null(); } + bool validate_ref(int* ops, Ref cell_ref, bool weak = false) const { + return cell_ref.not_null() && validate_ref_internal(ops, std::move(cell_ref), weak); + } + bool validate_ref(int ops, Ref cell_ref, bool weak = false) const { + return validate_ref(&ops, std::move(cell_ref), weak); + } bool validate_ref(Ref cell_ref, bool weak = false) const { - return cell_ref.not_null() && validate_ref_internal(std::move(cell_ref), weak); + return validate_ref(default_validate_max_cells, std::move(cell_ref), weak); + } + bool force_validate_ref(int* ops, Ref cell_ref) const { + return cell_ref.not_null() && validate_ref_internal(ops, std::move(cell_ref), false); + } + bool force_validate_ref(int ops, Ref cell_ref) const { + return force_validate_ref(&ops, std::move(cell_ref)); } bool force_validate_ref(Ref cell_ref) const { - return cell_ref.not_null() && validate_ref_internal(std::move(cell_ref), false); + return force_validate_ref(default_validate_max_cells, std::move(cell_ref)); } - bool validate_skip_ref(vm::CellSlice& cs, bool weak = false) const { - return validate_ref(cs.fetch_ref(), weak); + bool validate_skip_ref(int* ops, vm::CellSlice& cs, bool weak = false) const { + return validate_ref(ops, cs.fetch_ref(), weak); + } + bool validate_skip_ref(int ops, vm::CellSlice& cs, bool weak = false) const { + return validate_skip_ref(&ops, cs, weak); } virtual bool null_value(vm::CellBuilder& cb) const { return false; @@ -196,6 +229,7 @@ class TLB { virtual std::ostream& print_type(std::ostream& os) const { return os << ""; } + std::string get_type_name() const; virtual bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const; virtual bool print(PrettyPrinter& pp, const vm::CellSlice& cs) const { vm::CellSlice cs_copy{cs}; @@ -206,21 +240,27 @@ class TLB { bool print(PrettyPrinter& pp, Ref cs_ref) const { return print(pp, *cs_ref); } - bool print_skip(std::ostream& os, vm::CellSlice& cs, int indent = 0) const; - bool print(std::ostream& os, const vm::CellSlice& cs, int indent = 0) const; - bool print(std::ostream& os, Ref cs_ref, int indent = 0) const { - return print(os, *cs_ref, indent); + bool print_skip(std::ostream& os, vm::CellSlice& cs, int indent = 0, int rec_limit = 0) const; + bool print(std::ostream& os, const vm::CellSlice& cs, int indent = 0, int rec_limit = 0) const; + bool print(std::ostream& os, Ref cs_ref, int indent = 0, int rec_limit = 0) const { + return print(os, *cs_ref, indent, rec_limit); + } + bool print_ref(std::ostream& os, Ref cell_ref, int indent = 0, int rec_limit = 0) const; + bool print_ref(int rec_limit, std::ostream& os, Ref cell_ref, int indent = 0) const { + return print_ref(os, std::move(cell_ref), indent, rec_limit); } - bool print_ref(std::ostream& os, Ref cell_ref, int indent = 0) const; std::string as_string_skip(vm::CellSlice& cs, int indent = 0) const; std::string as_string(const vm::CellSlice& cs, int indent = 0) const; std::string as_string(Ref cs_ref, int indent = 0) const { return cs_ref.not_null() ? as_string(*cs_ref, indent) : ""; } std::string as_string_ref(Ref cell_ref, int indent = 0) const; + static inline size_t nat_abs(int x) { + return (x > 1) * 2 + (x & 1); + } protected: - bool validate_ref_internal(Ref cell_ref, bool weak = false) const; + bool validate_ref_internal(int* ops, Ref cell_ref, bool weak = false) const; }; static inline std::ostream& operator<<(std::ostream& os, const TLB& type) { @@ -229,29 +269,29 @@ static inline std::ostream& operator<<(std::ostream& os, const TLB& type) { struct TLB_Complex : TLB { bool skip(vm::CellSlice& cs) const override { - return validate_skip(cs); + return validate_skip(nullptr, cs); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override = 0; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override = 0; int get_size(const vm::CellSlice& cs) const override { return get_size_by_skip(cs); } - bool validate(const vm::CellSlice& cs, bool weak = false) const override { - return validate_by_skip(cs, weak); + bool validate(int* ops, const vm::CellSlice& cs, bool weak = false) const override { + return validate_by_skip(ops, cs, weak); } - bool validate_exact(const vm::CellSlice& cs, bool weak = false) const override { - return validate_by_skip_exact(cs, weak); + bool validate_exact(int* ops, const vm::CellSlice& cs, bool weak = false) const override { + return validate_by_skip_exact(ops, cs, weak); } bool extract(vm::CellSlice& cs) const override { return extract_by_skip(cs); } - bool validate_extract(vm::CellSlice& cs, bool weak = false) const override { - return validate_extract_by_skip(cs, weak); + bool validate_extract(int* ops, vm::CellSlice& cs, bool weak = false) const override { + return validate_extract_by_skip(ops, cs, weak); } - Ref validate_fetch(vm::CellSlice& cs, bool weak = false) const override { - return validate_fetch_by_skip(cs, weak); + Ref validate_fetch(int* ops, vm::CellSlice& cs, bool weak = false) const override { + return validate_fetch_by_skip(ops, cs, weak); } - Ref validate_prefetch(const vm::CellSlice& cs, bool weak = false) const override { - return validate_prefetch_by_skip(cs, weak); + Ref validate_prefetch(int* ops, const vm::CellSlice& cs, bool weak = false) const override { + return validate_prefetch_by_skip(ops, cs, weak); } td::RefInt256 as_integer(const vm::CellSlice& cs) const override { vm::CellSlice copy{cs}; @@ -264,6 +304,30 @@ struct TLB_Complex : TLB { } }; +class TlbTypeHolder : public td::CntObject { + const TLB* type{nullptr}; + char* data{nullptr}; + + public: + TlbTypeHolder() = default; + TlbTypeHolder(const TLB* _type) : type(_type), data(nullptr) { + } + TlbTypeHolder(const TLB* _type, char* _data) : type(_type), data(_data) { + } + ~TlbTypeHolder() override { + free(data); + } + const TLB* get() const { + return type; + } + const TLB& operator*() const { + return *type; + } + const TLB* operator->() const { + return type; + } +}; + static inline bool add_chk(int x, int y, int z) { return x + y == z && z >= 0; } @@ -427,15 +491,20 @@ bool store_from(vm::CellBuilder& cb, const T& tlb_type, Ref field namespace tlb { struct PrettyPrinter { + enum { default_print_limit = 4096 }; std::ostream& os; int indent; int level; bool failed; bool nl_used; int mode; + int limit{default_print_limit}; PrettyPrinter(std::ostream& _os, int _indent = 0, int _mode = 1) : os(_os), indent(_indent), level(0), failed(false), nl_used(false), mode(_mode) { } + PrettyPrinter(int _limit, std::ostream& _os, int _indent = 0, int _mode = 1) + : os(_os), indent(_indent), level(0), failed(false), nl_used(false), mode(_mode), limit(_limit) { + } ~PrettyPrinter(); bool ok() const { return !failed && !level; @@ -460,6 +529,14 @@ struct PrettyPrinter { bool field_int(long long value, std::string name); bool field_uint(unsigned long long value); bool field_uint(unsigned long long value, std::string name); + bool register_recursive_call() { + return limit--; + } + void set_limit(int new_limit) { + if (new_limit > 0) { + limit = new_limit; + } + } bool out(std::string str) { os << str; return true; @@ -504,6 +581,25 @@ struct PrettyPrinter { namespace tlb { +class TypenameLookup { + std::map types; + + public: + typedef std::function simple_register_func_t; + typedef std::function register_func_t; + TypenameLookup() = default; + TypenameLookup(register_func_t func) { + register_types(func); + } + bool register_type(const char* name, const TLB* tp); + bool register_types(register_func_t func); + const TLB* lookup(std::string str) const; +}; + +} // namespace tlb + +namespace tlb { + struct False final : TLB { int get_size(const vm::CellSlice& cs) const override { return -1; @@ -554,23 +650,23 @@ struct FwdT final : TLB { bool skip(vm::CellSlice& cs) const override { return X.skip(cs); } - bool validate(const vm::CellSlice& cs, bool weak = false) const override { - return X.validate(cs, weak); + bool validate(int* ops, const vm::CellSlice& cs, bool weak = false) const override { + return X.validate(ops, cs, weak); } - Ref validate_fetch(vm::CellSlice& cs, bool weak = false) const override { - return X.validate_fetch(cs, weak); + Ref validate_fetch(int* ops, vm::CellSlice& cs, bool weak = false) const override { + return X.validate_fetch(ops, cs, weak); } - Ref validate_prefetch(const vm::CellSlice& cs, bool weak = false) const override { - return X.validate_prefetch(cs, weak); + Ref validate_prefetch(int* ops, const vm::CellSlice& cs, bool weak = false) const override { + return X.validate_prefetch(ops, cs, weak); } bool extract(vm::CellSlice& cs) const override { return X.extract(cs); } - bool validate_extract(vm::CellSlice& cs, bool weak = false) const override { - return X.validate_extract(cs, weak); + bool validate_extract(int* ops, vm::CellSlice& cs, bool weak = false) const override { + return X.validate_extract(ops, cs, weak); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override { - return X.validate_skip(cs, weak); + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override { + return X.validate_skip(ops, cs, weak); } bool skip_copy(vm::CellBuilder& cb, vm::CellSlice& cs) const override { return X.skip_copy(cb, cs); @@ -665,10 +761,10 @@ struct NatLess final : TLB { int get_size(const vm::CellSlice& cs) const override { return n >= 0 ? w : -1; } - bool validate(const vm::CellSlice& cs, bool weak = false) const override { + bool validate(int* ops, const vm::CellSlice& cs, bool weak = false) const override { return n >= 0 && (unsigned)cs.prefetch_ulong(w) <= (unsigned)n; } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override { + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override { return n >= 0 && (unsigned)cs.fetch_ulong(w) <= (unsigned)n; } unsigned long long as_uint(const vm::CellSlice& cs) const override { @@ -688,10 +784,10 @@ struct NatLeq final : TLB { int get_size(const vm::CellSlice& cs) const override { return n >= 0 ? w : -1; } - bool validate(const vm::CellSlice& cs, bool weak = false) const override { + bool validate(int* ops, const vm::CellSlice& cs, bool weak = false) const override { return n >= 0 && (unsigned)cs.prefetch_ulong(w) <= (unsigned)n; } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override { + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override { return n >= 0 && (unsigned)cs.fetch_ulong(w) <= (unsigned)n; } unsigned long long as_uint(const vm::CellSlice& cs) const override { @@ -710,7 +806,7 @@ struct TupleT final : TLB_Complex { TupleT(int _n, const TLB& _X) : n(_n), X(_X) { } bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; int get_tag(const vm::CellSlice& cs) const override { return 0; } @@ -725,8 +821,8 @@ struct CondT final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return !n || X.skip(cs); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override { - return !n || (n > 0 && X.validate_skip(cs, weak)); + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override { + return !n || (n > 0 && X.validate_skip(ops, cs, weak)); } int get_tag(const vm::CellSlice& cs) const override { return 0; @@ -747,8 +843,8 @@ struct Cond final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return !n || field_type.skip(cs); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override { - return !n || (n > 0 && field_type.validate_skip(cs, weak)); + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override { + return !n || (n > 0 && field_type.validate_skip(ops, cs, weak)); } int get_tag(const vm::CellSlice& cs) const override { return 0; @@ -844,7 +940,7 @@ struct Maybe : TLB_Complex { Maybe(Args... args) : field_type(args...) { } bool skip(vm::CellSlice& cs) const override; - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override; int get_tag(const vm::CellSlice& cs) const override { return cs.have(1) ? (int)cs.prefetch_ulong(1) : -1; } @@ -867,10 +963,10 @@ bool Maybe::skip(vm::CellSlice& cs) const { } template -bool Maybe::validate_skip(vm::CellSlice& cs, bool weak) const { +bool Maybe::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { int t = get_tag(cs); if (t > 0) { - return cs.advance(1) && field_type.validate_skip(cs, weak); + return cs.advance(1) && field_type.validate_skip(ops, cs, weak); } else if (!t) { return cs.advance(1); } else { @@ -918,11 +1014,11 @@ struct RefTo final : TLB { int get_size(const vm::CellSlice& cs) const override { return 0x10000; } - bool validate(const vm::CellSlice& cs, bool weak = false) const override { - return cs.size_refs() ? ref_type.validate_ref(cs.prefetch_ref(), weak) : false; + bool validate(int* ops, const vm::CellSlice& cs, bool weak = false) const override { + return cs.size_refs() ? ref_type.validate_ref(ops, cs.prefetch_ref(), weak) : false; } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override { - return ref_type.validate_skip_ref(cs, weak); + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override { + return ref_type.validate_skip_ref(ops, cs, weak); } std::ostream& print_type(std::ostream& os) const override { return os << '^' << ref_type; @@ -939,11 +1035,11 @@ struct RefT final : TLB { int get_size(const vm::CellSlice& cs) const override { return 0x10000; } - bool validate(const vm::CellSlice& cs, bool weak = false) const override { - return X.validate_ref(cs.prefetch_ref(), weak); + bool validate(int* ops, const vm::CellSlice& cs, bool weak = false) const override { + return X.validate_ref(ops, cs.prefetch_ref(), weak); } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override { - return X.validate_skip_ref(cs, weak); + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override { + return X.validate_skip_ref(ops, cs, weak); } std::ostream& print_type(std::ostream& os) const override { return os << '^' << X; @@ -960,9 +1056,10 @@ struct Either final : TLB_Complex { bool skip(vm::CellSlice& cs) const override { return cs.have(1) ? (cs.fetch_ulong(1) ? right_type.skip(cs) : left_type.skip(cs)) : false; } - bool validate_skip(vm::CellSlice& cs, bool weak = false) const override { - return cs.have(1) ? (cs.fetch_ulong(1) ? right_type.validate_skip(cs, weak) : left_type.validate_skip(cs, weak)) - : false; + bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override { + return cs.have(1) + ? (cs.fetch_ulong(1) ? right_type.validate_skip(ops, cs, weak) : left_type.validate_skip(ops, cs, weak)) + : false; } int get_tag(const vm::CellSlice& cs) const override { return (int)cs.prefetch_ulong(1); diff --git a/submodules/ton/tonlib-src/crypto/vm/arithops.cpp b/submodules/ton/tonlib-src/crypto/vm/arithops.cpp index 19279cf167..25b6735386 100644 --- a/submodules/ton/tonlib-src/crypto/vm/arithops.cpp +++ b/submodules/ton/tonlib-src/crypto/vm/arithops.cpp @@ -14,15 +14,15 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include #include "vm/arithops.h" #include "vm/log.h" #include "vm/opctable.h" #include "vm/stack.hpp" -#include "vm/continuation.h" #include "vm/excno.hpp" +#include "vm/vm.h" #include "common/bigint.hpp" #include "common/refint.h" @@ -389,7 +389,7 @@ int exec_muldivmod(VmState* st, unsigned args, int quiet) { auto x = stack.pop_int(); typename td::BigInt256::DoubleInt tmp{0}; tmp.add_mul(*x, *y); - auto q = td::RefInt256{true}; + auto q = td::make_refint(); tmp.mod_div(*z, q.unique_write(), round_mode); switch ((args >> 2) & 3) { case 1: @@ -401,7 +401,7 @@ int exec_muldivmod(VmState* st, unsigned args, int quiet) { stack.push_int_quiet(std::move(q), quiet); // fallthrough case 2: - stack.push_int_quiet(td::RefInt256{true, tmp}, quiet); + stack.push_int_quiet(td::make_refint(tmp), quiet); break; } return 0; @@ -450,17 +450,17 @@ int exec_mulshrmod(VmState* st, unsigned args, int mode) { switch ((args >> 2) & 3) { case 1: tmp.rshift(z, round_mode).normalize(); - stack.push_int_quiet(td::RefInt256{true, tmp}, mode & 1); + stack.push_int_quiet(td::make_refint(tmp), mode & 1); break; case 3: { typename td::BigInt256::DoubleInt tmp2{tmp}; tmp2.rshift(z, round_mode).normalize(); - stack.push_int_quiet(td::RefInt256{true, tmp2}, mode & 1); + stack.push_int_quiet(td::make_refint(tmp2), mode & 1); } // fallthrough case 2: tmp.mod_pow2(z, round_mode).normalize(); - stack.push_int_quiet(td::RefInt256{true, tmp}, mode & 1); + stack.push_int_quiet(td::make_refint(tmp), mode & 1); break; } return 0; @@ -524,24 +524,24 @@ int exec_shldivmod(VmState* st, unsigned args, int mode) { tmp <<= y; switch ((args >> 2) & 3) { case 1: { - auto q = td::RefInt256{true}; + auto q = td::make_refint(); tmp.mod_div(*z, q.unique_write(), round_mode); q.unique_write().normalize(); stack.push_int_quiet(std::move(q), mode & 1); break; } case 3: { - auto q = td::RefInt256{true}; + auto q = td::make_refint(); tmp.mod_div(*z, q.unique_write(), round_mode); q.unique_write().normalize(); stack.push_int_quiet(std::move(q), mode & 1); - stack.push_int_quiet(td::RefInt256{true, tmp}, mode & 1); + stack.push_int_quiet(td::make_refint(tmp), mode & 1); break; } case 2: { typename td::BigInt256::DoubleInt tmp2; tmp.mod_div(*z, tmp2, round_mode); - stack.push_int_quiet(td::RefInt256{true, tmp}, mode & 1); + stack.push_int_quiet(td::make_refint(tmp), mode & 1); break; } } @@ -740,7 +740,7 @@ int exec_bitsize(VmState* st, bool sgnd, bool quiet) { } else if (!quiet) { throw VmError{Excno::range_chk, "CHKSIZE for negative integer"}; } else { - stack.push_int_quiet(td::RefInt256{true}, quiet); + stack.push_int_quiet(td::make_refint(), quiet); } return 0; } diff --git a/submodules/ton/tonlib-src/crypto/vm/cellops.cpp b/submodules/ton/tonlib-src/crypto/vm/cellops.cpp index 5346e16851..cc1102846e 100644 --- a/submodules/ton/tonlib-src/crypto/vm/cellops.cpp +++ b/submodules/ton/tonlib-src/crypto/vm/cellops.cpp @@ -14,16 +14,16 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include #include "vm/cellops.h" #include "vm/log.h" #include "vm/opctable.h" #include "vm/stack.hpp" -#include "vm/continuation.h" #include "vm/excno.hpp" #include "vm/vmstate.h" +#include "vm/vm.h" #include "common/bigint.hpp" #include "common/refint.h" @@ -814,6 +814,9 @@ void register_cell_serialize_ops(OpcodeTable& cp0) { compute_len_store_const_ref)) .insert(OpcodeInstr::mksimple(0xcf23, 16, "ENDXC", exec_builder_to_special_cell)) .insert(OpcodeInstr::mkfixed(0xcf28 >> 2, 14, 2, dump_store_le_int, exec_store_le_int)) + .insert(OpcodeInstr::mksimple( + 0xcf30, 16, "BDEPTH", + std::bind(exec_int_builder_func, _1, "BDEPTH", [](Ref b) { return b->get_depth(); }))) .insert(OpcodeInstr::mksimple( 0xcf31, 16, "BBITS", std::bind(exec_int_builder_func, _1, "BBITS", [](Ref b) { return b->size(); }))) @@ -1321,6 +1324,22 @@ int exec_load_same(VmState* st, const char* name, int x) { return 0; } +int exec_cell_depth(VmState* st) { + Stack& stack = st->get_stack(); + VM_LOG(st) << "execute CDEPTH"; + auto cell = stack.pop_maybe_cell(); + stack.push_smallint(cell.not_null() ? cell->get_depth() : 0); + return 0; +} + +int exec_slice_depth(VmState* st) { + Stack& stack = st->get_stack(); + VM_LOG(st) << "execute SDEPTH"; + auto cs = stack.pop_cellslice(); + stack.push_smallint(cs->get_depth()); + return 0; +} + void register_cell_deserialize_ops(OpcodeTable& cp0) { using namespace std::placeholders; cp0.insert(OpcodeInstr::mksimple(0xd0, 8, "CTOS", exec_cell_to_slice)) @@ -1407,7 +1426,9 @@ void register_cell_deserialize_ops(OpcodeTable& cp0) { .insert(OpcodeInstr::mkfixed(0xd75, 12, 4, dump_load_le_int, exec_load_le_int)) .insert(OpcodeInstr::mksimple(0xd760, 16, "LDZEROES", std::bind(exec_load_same, _1, "LDZEROES", 0))) .insert(OpcodeInstr::mksimple(0xd761, 16, "LDONES", std::bind(exec_load_same, _1, "LDONES", 1))) - .insert(OpcodeInstr::mksimple(0xd762, 16, "LDSAME", std::bind(exec_load_same, _1, "LDSAME", -1))); + .insert(OpcodeInstr::mksimple(0xd762, 16, "LDSAME", std::bind(exec_load_same, _1, "LDSAME", -1))) + .insert(OpcodeInstr::mksimple(0xd764, 16, "SDEPTH", exec_slice_depth)) + .insert(OpcodeInstr::mksimple(0xd765, 16, "CDEPTH", exec_cell_depth)); } void register_cell_ops(OpcodeTable& cp0) { diff --git a/submodules/ton/tonlib-src/crypto/vm/cells/CellBuilder.cpp b/submodules/ton/tonlib-src/crypto/vm/cells/CellBuilder.cpp index 223959bdc4..1c3fcdef8a 100644 --- a/submodules/ton/tonlib-src/crypto/vm/cells/CellBuilder.cpp +++ b/submodules/ton/tonlib-src/crypto/vm/cells/CellBuilder.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "vm/cells/CellBuilder.h" @@ -52,18 +52,26 @@ Ref CellBuilder::finalize_copy(bool special) const { } auto res = DataCell::create(data, size(), td::span(refs.data(), size_refs()), special); if (res.is_error()) { - LOG(ERROR) << res.error(); + LOG(DEBUG) << res.error(); throw CellWriteError{}; } - CHECK(res.ok().not_null()); - return res.move_as_ok(); + auto cell = res.move_as_ok(); + CHECK(cell.not_null()); + if (vm_state_interface) { + vm_state_interface->register_new_cell(cell); + if (cell.is_null()) { + LOG(DEBUG) << "cannot register new data cell"; + throw CellWriteError{}; + } + } + return cell; } Ref CellBuilder::finalize_novm(bool special) { auto res = DataCell::create(data, size(), td::mutable_span(refs.data(), size_refs()), special); bits = refs_cnt = 0; if (res.is_error()) { - LOG(ERROR) << res.error(); + LOG(DEBUG) << res.error(); throw CellWriteError{}; } CHECK(res.ok().not_null()); @@ -72,10 +80,17 @@ Ref CellBuilder::finalize_novm(bool special) { Ref CellBuilder::finalize(bool special) { auto* vm_state_interface = VmStateInterface::get(); - if (vm_state_interface) { - vm_state_interface->register_cell_create(); + if (!vm_state_interface) { + return finalize_novm(special); } - return finalize_novm(special); + vm_state_interface->register_cell_create(); + auto cell = finalize_novm(special); + vm_state_interface->register_new_cell(cell); + if (cell.is_null()) { + LOG(DEBUG) << "cannot register new data cell"; + throw CellWriteError{}; + } + return cell; } Ref CellBuilder::create_pruned_branch(Ref cell, td::uint32 new_level, td::uint32 virt_level) { @@ -87,6 +102,7 @@ Ref CellBuilder::create_pruned_branch(Ref cell, td::uint32 new_level } return do_create_pruned_branch(std::move(cell), new_level, virt_level); } + Ref CellBuilder::do_create_pruned_branch(Ref cell, td::uint32 new_level, td::uint32 virt_level) { auto level_mask = cell->get_level_mask().apply(virt_level); auto level = level_mask.get_level(); @@ -371,6 +387,14 @@ CellBuilder& CellBuilder::store_ref(Ref ref) { return ensure_pass(store_ref_bool(std::move(ref))); } +td::uint16 CellBuilder::get_depth() const { + int d = 0; + for (unsigned i = 0; i < refs_cnt; i++) { + d = std::max(d, 1 + refs[i]->get_depth()); + } + return static_cast(d); +} + bool CellBuilder::append_data_cell_bool(const DataCell& cell) { unsigned len = cell.size(); if (can_extend_by(len, cell.size_refs())) { @@ -460,6 +484,16 @@ bool CellBuilder::append_cellslice_chk(Ref cs_ref, unsigned size_ext) return cs_ref.not_null() && append_cellslice_chk(*cs_ref, size_ext); } +CellSlice CellSlice::clone() const { + CellBuilder cb; + Ref cell; + if (cb.append_cellslice_bool(*this) && cb.finalize_to(cell)) { + return CellSlice{NoVmOrd(), std::move(cell)}; + } else { + return {}; + } +} + bool CellBuilder::append_bitstring(const td::BitString& bs) { return store_bits_bool(bs.cbits(), bs.size()); } @@ -536,11 +570,11 @@ CellBuilder* CellBuilder::make_copy() const { return c; } -CellSlice CellBuilder::as_cellslice() const& { +CellSlice CellBuilder::as_cellslice() const & { return CellSlice{finalize_copy()}; } -Ref CellBuilder::as_cellslice_ref() const& { +Ref CellBuilder::as_cellslice_ref() const & { return Ref{true, finalize_copy()}; } diff --git a/submodules/ton/tonlib-src/crypto/vm/cells/CellBuilder.h b/submodules/ton/tonlib-src/crypto/vm/cells/CellBuilder.h index 0095018e44..bcd2434ecf 100644 --- a/submodules/ton/tonlib-src/crypto/vm/cells/CellBuilder.h +++ b/submodules/ton/tonlib-src/crypto/vm/cells/CellBuilder.h @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once #include "vm/cells/DataCell.h" @@ -78,6 +78,7 @@ class CellBuilder : public td::CntObject { const unsigned char* get_data() const { return data; } + td::uint16 get_depth() const; td::ConstBitPtr data_bits() const { return data; } @@ -85,6 +86,10 @@ class CellBuilder : public td::CntObject { return idx < refs_cnt ? refs[idx] : Ref{}; } void reset(); + bool reset_bool() { + reset(); + return true; + } CellBuilder& operator=(const CellBuilder&); CellBuilder& operator=(CellBuilder&&); CellBuilder& store_bytes(const char* str, std::size_t len); diff --git a/submodules/ton/tonlib-src/crypto/vm/cells/CellSlice.cpp b/submodules/ton/tonlib-src/crypto/vm/cells/CellSlice.cpp index bb550a6969..0d539c74e6 100644 --- a/submodules/ton/tonlib-src/crypto/vm/cells/CellSlice.cpp +++ b/submodules/ton/tonlib-src/crypto/vm/cells/CellSlice.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "vm/cells/CellSlice.h" #include "vm/excno.hpp" @@ -218,6 +218,17 @@ unsigned CellSlice::get_level() const { return l; } +Ref CellSlice::get_base_cell() const { + if (cell.is_null()) { + return {}; + } + auto res = cell->virtualize(virt); + if (!tree_node.empty()) { + res = UsageCell::create(std::move(res), tree_node); + } + return res; +} + bool CellSlice::advance(unsigned bits) { if (have(bits)) { bits_st += bits; @@ -583,8 +594,7 @@ td::RefInt256 CellSlice::fetch_int256(unsigned bits, bool sgnd) { if (!have(bits)) { return {}; } else if (bits < td::BigInt256::word_shift) { - long long val = sgnd ? fetch_long(bits) : fetch_ulong(bits); - return td::RefInt256{true, val}; + return td::make_refint(sgnd ? fetch_long(bits) : fetch_ulong(bits)); } else { td::RefInt256 res{true}; res.unique_write().import_bits(data_bits(), bits, sgnd); @@ -597,8 +607,7 @@ td::RefInt256 CellSlice::prefetch_int256(unsigned bits, bool sgnd) const { if (!have(bits)) { return {}; } else if (bits < td::BigInt256::word_shift) { - long long val = sgnd ? prefetch_long(bits) : prefetch_ulong(bits); - return td::RefInt256{true, val}; + return td::make_refint(sgnd ? prefetch_long(bits) : prefetch_ulong(bits)); } else { td::RefInt256 res{true}; res.unique_write().import_bits(data_bits(), bits, sgnd); @@ -608,15 +617,15 @@ td::RefInt256 CellSlice::prefetch_int256(unsigned bits, bool sgnd) const { td::RefInt256 CellSlice::prefetch_int256_zeroext(unsigned bits, bool sgnd) const { if (bits > 256u + sgnd) { - return td::RefInt256{false}; + return td::make_refint(); } else { unsigned ld_bits = std::min(bits, size()); if (bits < td::BigInt256::word_shift) { long long val = sgnd ? prefetch_long(ld_bits) : prefetch_ulong(ld_bits); val <<= bits - ld_bits; - return td::RefInt256{true, val}; + return td::make_refint(val); } else { - td::RefInt256 res{true}; + auto res = td::make_refint(); res.unique_write().import_bits(data_bits(), ld_bits, sgnd); res <<= bits - ld_bits; return res; @@ -765,6 +774,14 @@ bool CellSlice::fetch_maybe_ref(Ref& res) { } } +td::uint16 CellSlice::get_depth() const { + int d = 0; + for (unsigned i = 0; i < size_refs(); ++i) { + d = std::max(d, prefetch_ref(i)->get_depth() + 1); + } + return static_cast(d); +} + bool CellSlice::begins_with(unsigned bits, unsigned long long value) const { return have(bits) && !((prefetch_ulong(bits) ^ value) & ((1ULL << bits) - 1)); } @@ -969,13 +986,18 @@ void CellSlice::dump_hex(std::ostream& os, int mode, bool endl) const { } } -void CellSlice::print_rec(std::ostream& os, int indent) const { +bool CellSlice::print_rec(std::ostream& os, int* limit, int indent) const { for (int i = 0; i < indent; i++) { os << ' '; } + if (!limit || *limit <= 0) { + os << "" << std::endl; + return false; + } + --*limit; if (cell.is_null()) { os << "NULL" << std::endl; - return; + return true; } if (is_special()) { os << "SPECIAL "; @@ -983,8 +1005,20 @@ void CellSlice::print_rec(std::ostream& os, int indent) const { os << "x{" << as_bitslice().to_hex() << '}' << std::endl; for (unsigned i = 0; i < size_refs(); i++) { CellSlice cs{NoVm(), prefetch_ref(i)}; - cs.print_rec(os, indent + 1); + if (!cs.print_rec(os, limit, indent + 1)) { + return false; + } } + return true; +} + +bool CellSlice::print_rec(std::ostream& os, int indent) const { + int limit = default_recursive_print_limit; + return print_rec(os, &limit, indent); +} + +bool CellSlice::print_rec(int limit, std::ostream& os, int indent) const { + return print_rec(os, &limit, indent); } td::StringBuilder& operator<<(td::StringBuilder& sb, const CellSlice& cs) { @@ -1015,7 +1049,7 @@ std::ostream& operator<<(std::ostream& os, Ref cs_ref) { VirtualCell::LoadedCell load_cell_slice_impl(const Ref& cell, bool* can_be_special) { auto* vm_state_interface = VmStateInterface::get(); if (vm_state_interface) { - vm_state_interface->register_cell_load(); + vm_state_interface->register_cell_load(cell->get_hash()); } auto r_loaded_cell = cell->load_cell(); if (r_loaded_cell.is_error()) { diff --git a/submodules/ton/tonlib-src/crypto/vm/cells/CellSlice.h b/submodules/ton/tonlib-src/crypto/vm/cells/CellSlice.h index 433344f982..a2e528d685 100644 --- a/submodules/ton/tonlib-src/crypto/vm/cells/CellSlice.h +++ b/submodules/ton/tonlib-src/crypto/vm/cells/CellSlice.h @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once @@ -44,6 +44,7 @@ class CellSlice : public td::CntObject { public: static constexpr long long fetch_long_eof = (static_cast(-1LL) << 63); static constexpr unsigned long long fetch_ulong_eof = (unsigned long long)-1LL; + enum { default_recursive_print_limit = 100 }; struct CellReadError {}; CellSlice(NoVm, Ref cell_ref); @@ -129,6 +130,7 @@ class CellSlice : public td::CntObject { const unsigned char* data() const { return cell->get_data(); } + td::uint16 get_depth() const; td::ConstBitPtr data_bits() const { return td::ConstBitPtr{data(), (int)cur_pos()}; } @@ -137,6 +139,7 @@ class CellSlice : public td::CntObject { } unsigned get_cell_level() const; unsigned get_level() const; + Ref get_base_cell() const; // be careful with this one! int fetch_octet(); int prefetch_octet() const; unsigned long long prefetch_ulong_top(unsigned& bits) const; @@ -251,7 +254,9 @@ class CellSlice : public td::CntObject { bool contents_equal(const CellSlice& cs2) const; void dump(std::ostream& os, int level = 0, bool endl = true) const; void dump_hex(std::ostream& os, int mode = 0, bool endl = false) const; - void print_rec(std::ostream& os, int indent = 0) const; + bool print_rec(std::ostream& os, int indent = 0) const; + bool print_rec(std::ostream& os, int* limit, int indent = 0) const; + bool print_rec(int limit, std::ostream& os, int indent = 0) const; void error() const { throw CellReadError{}; } @@ -274,6 +279,7 @@ class CellSlice : public td::CntObject { offs = std::min(offs, size()); return CellSlice{*this, size() - offs, size_refs(), offs, 0}; } + CellSlice clone() const; private: void init_bits_refs(); diff --git a/submodules/ton/tonlib-src/crypto/vm/cells/CellString.cpp b/submodules/ton/tonlib-src/crypto/vm/cells/CellString.cpp index ad2cbf5f8f..9889dc8e2b 100644 --- a/submodules/ton/tonlib-src/crypto/vm/cells/CellString.cpp +++ b/submodules/ton/tonlib-src/crypto/vm/cells/CellString.cpp @@ -1,3 +1,21 @@ +/* + This file is part of TON Blockchain Library. + + TON Blockchain Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + TON Blockchain Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with TON Blockchain Library. If not, see . + + Copyright 2019-2020 Telegram Systems LLP +*/ #include "CellString.h" #include "td/utils/misc.h" @@ -61,4 +79,79 @@ td::Result CellString::load(CellSlice &cs, unsigned int top_bits) { CHECK(to.offs == (int)size); return res; } + +td::Status CellText::store(CellBuilder &cb, td::Slice slice, unsigned int top_bits) { + td::uint32 size = td::narrow_cast(slice.size() * 8); + return store(cb, td::BitSlice(slice.ubegin(), size), top_bits); +} + +td::Status CellText::store(CellBuilder &cb, td::BitSlice slice, unsigned int top_bits) { + if (slice.size() > max_bytes * 8) { + return td::Status::Error("String is too long (1)"); + } + if (cb.remaining_bits() < 16) { + return td::Status::Error("Not enough space in a builder"); + } + if (top_bits < 16) { + return td::Status::Error("Need at least 16 top bits"); + } + if (slice.size() == 0) { + cb.store_long(0, 8); + return td::Status::OK(); + } + unsigned int head = td::min(slice.size(), td::min(cb.remaining_bits(), top_bits) - 16) / 8 * 8; + auto max_bits = vm::Cell::max_bits / 8 * 8; + auto depth = 1 + (slice.size() - head + max_bits - 8 - 1) / (max_bits - 8); + if (depth > max_chain_length) { + return td::Status::Error("String is too long (2)"); + } + cb.store_long(depth, 8); + cb.store_long(head / 8, 8); + cb.append_bitslice(slice.subslice(0, head)); + slice.advance(head); + if (slice.size() == 0) { + return td::Status::OK(); + } + cb.store_ref(do_store(std::move(slice))); + return td::Status::OK(); +} + +td::Ref CellText::do_store(td::BitSlice slice) { + vm::CellBuilder cb; + unsigned int head = td::min(slice.size(), cb.remaining_bits() - 8) / 8 * 8; + cb.store_long(head / 8, 8); + cb.append_bitslice(slice.subslice(0, head)); + slice.advance(head); + if (slice.size() != 0) { + cb.store_ref(do_store(std::move(slice))); + } + return cb.finalize(); +} + +template +void CellText::for_each(F &&f, CellSlice cs) { + auto depth = cs.fetch_ulong(8); + + for (td::uint32 i = 0; i < depth; i++) { + auto size = cs.fetch_ulong(8); + f(cs.fetch_bits(td::narrow_cast(size) * 8)); + if (i + 1 < depth) { + cs = vm::load_cell_slice(cs.prefetch_ref()); + } + } +} + +td::Result CellText::load(CellSlice &cs) { + unsigned int size = 0; + for_each([&](auto slice) { size += slice.size(); }, cs); + if (size % 8 != 0) { + return td::Status::Error("Size is not divisible by 8"); + } + std::string res(size / 8, 0); + + td::BitPtr to(td::MutableSlice(res).ubegin()); + for_each([&](auto slice) { to.concat(slice); }, cs); + CHECK(to.offs == (int)size); + return res; +} } // namespace vm diff --git a/submodules/ton/tonlib-src/crypto/vm/cells/CellString.h b/submodules/ton/tonlib-src/crypto/vm/cells/CellString.h index 89c933d876..ab93203f88 100644 --- a/submodules/ton/tonlib-src/crypto/vm/cells/CellString.h +++ b/submodules/ton/tonlib-src/crypto/vm/cells/CellString.h @@ -1,3 +1,21 @@ +/* + This file is part of TON Blockchain Library. + + TON Blockchain Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + TON Blockchain Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with TON Blockchain Library. If not, see . + + Copyright 2019-2020 Telegram Systems LLP +*/ #pragma once #include "td/utils/Status.h" @@ -13,10 +31,35 @@ class CellString { static td::Status store(CellBuilder &cb, td::Slice slice, unsigned int top_bits = Cell::max_bits); static td::Status store(CellBuilder &cb, td::BitSlice slice, unsigned int top_bits = Cell::max_bits); static td::Result load(CellSlice &cs, unsigned int top_bits = Cell::max_bits); + static td::Result> create(td::Slice slice, unsigned int top_bits = Cell::max_bits) { + vm::CellBuilder cb; + TRY_STATUS(store(cb, slice, top_bits)); + return cb.finalize(); + } private: template static void for_each(F &&f, CellSlice &cs, unsigned int top_bits = Cell::max_bits); }; +class CellText { + public: + static constexpr unsigned int max_bytes = 1024; + static constexpr unsigned int max_chain_length = 16; + + static td::Status store(CellBuilder &cb, td::Slice slice, unsigned int top_bits = Cell::max_bits); + static td::Status store(CellBuilder &cb, td::BitSlice slice, unsigned int top_bits = Cell::max_bits); + static td::Result load(CellSlice &cs); + static td::Result> create(td::Slice slice, unsigned int top_bits = Cell::max_bits) { + vm::CellBuilder cb; + TRY_STATUS(store(cb, slice, top_bits)); + return cb.finalize(); + } + + private: + template + static void for_each(F &&f, CellSlice cs); + static td::Ref do_store(td::BitSlice slice); +}; + } // namespace vm diff --git a/submodules/ton/tonlib-src/crypto/vm/cells/MerkleProof.cpp b/submodules/ton/tonlib-src/crypto/vm/cells/MerkleProof.cpp index a373e80468..105c74c167 100644 --- a/submodules/ton/tonlib-src/crypto/vm/cells/MerkleProof.cpp +++ b/submodules/ton/tonlib-src/crypto/vm/cells/MerkleProof.cpp @@ -143,19 +143,80 @@ Ref MerkleProof::virtualize(Ref cell, int virtualization) { return virtualize_raw(r_raw.move_as_ok(), {0 /*level*/, static_cast(virtualization)}); } +class MerkleProofCombineFast { + public: + MerkleProofCombineFast(Ref a, Ref b) : a_(std::move(a)), b_(std::move(b)) { + } + td::Result> run() { + TRY_RESULT_ASSIGN(a_, unpack_proof(a_)); + TRY_RESULT_ASSIGN(b_, unpack_proof(b_)); + TRY_RESULT(res, run_raw()); + return CellBuilder::create_merkle_proof(std::move(res)); + } + + td::Result> run_raw() { + if (a_->get_hash(0) != b_->get_hash(0)) { + return td::Status::Error("Can't combine MerkleProofs with different roots"); + } + return merge(a_, b_, 0); + } + + private: + Ref a_; + Ref b_; + + Ref merge(Ref a, Ref b, td::uint32 merkle_depth) { + if (a->get_hash() == b->get_hash()) { + return a; + } + if (a->get_level() == merkle_depth) { + return a; + } + if (b->get_level() == merkle_depth) { + return b; + } + + CellSlice csa(NoVm(), a); + CellSlice csb(NoVm(), b); + + if (csa.is_special() && csa.special_type() == vm::Cell::SpecialType::PrunnedBranch) { + return b; + } + if (csb.is_special() && csb.special_type() == vm::Cell::SpecialType::PrunnedBranch) { + return a; + } + + CHECK(csa.size_refs() != 0); + + auto child_merkle_depth = csa.child_merkle_depth(merkle_depth); + + CellBuilder cb; + cb.store_bits(csa.fetch_bits(csa.size())); + for (unsigned i = 0; i < csa.size_refs(); i++) { + cb.store_ref(merge(csa.prefetch_ref(i), csb.prefetch_ref(i), child_merkle_depth)); + } + return cb.finalize(csa.is_special()); + } +}; + class MerkleProofCombine { public: MerkleProofCombine(Ref a, Ref b) : a_(std::move(a)), b_(std::move(b)) { } td::Result> run() { - TRY_RESULT(a, unpack_proof(a_)); - TRY_RESULT(b, unpack_proof(b_)); - if (a->get_hash(0) != b->get_hash(0)) { + TRY_RESULT_ASSIGN(a_, unpack_proof(a_)); + TRY_RESULT_ASSIGN(b_, unpack_proof(b_)); + TRY_RESULT(res, run_raw()); + return CellBuilder::create_merkle_proof(std::move(res)); + } + + td::Result> run_raw() { + if (a_->get_hash(0) != b_->get_hash(0)) { return td::Status::Error("Can't combine MerkleProofs with different roots"); } - dfs(a, 0); - dfs(b, 0); - return CellBuilder::create_merkle_proof(create_A(a, 0, 0)); + dfs(a_, 0); + dfs(b_, 0); + return create_A(a_, 0, 0); } private: @@ -262,6 +323,30 @@ Ref MerkleProof::combine(Ref a, Ref b) { return res.move_as_ok(); } +Ref MerkleProof::combine_fast(Ref a, Ref b) { + auto res = MerkleProofCombineFast(std::move(a), std::move(b)).run(); + if (res.is_error()) { + return {}; + } + return res.move_as_ok(); +} + +Ref MerkleProof::combine_raw(Ref a, Ref b) { + auto res = MerkleProofCombine(std::move(a), std::move(b)).run_raw(); + if (res.is_error()) { + return {}; + } + return res.move_as_ok(); +} + +Ref MerkleProof::combine_fast_raw(Ref a, Ref b) { + auto res = MerkleProofCombineFast(std::move(a), std::move(b)).run_raw(); + if (res.is_error()) { + return {}; + } + return res.move_as_ok(); +} + MerkleProofBuilder::MerkleProofBuilder(Ref root) : usage_tree(std::make_shared()), orig_root(std::move(root)) { usage_root = UsageCell::create(orig_root, usage_tree->root_ptr()); diff --git a/submodules/ton/tonlib-src/crypto/vm/cells/MerkleProof.h b/submodules/ton/tonlib-src/crypto/vm/cells/MerkleProof.h index 5b3b8ebcef..41788c5f7f 100644 --- a/submodules/ton/tonlib-src/crypto/vm/cells/MerkleProof.h +++ b/submodules/ton/tonlib-src/crypto/vm/cells/MerkleProof.h @@ -38,12 +38,15 @@ class MerkleProof { static Ref virtualize(Ref cell, int virtualization); static Ref combine(Ref a, Ref b); + static Ref combine_fast(Ref a, Ref b); // works with upwrapped proofs // works fine with cell of non-zero level, but this is not supported (yet?) in MerkeProof special cell static Ref generate_raw(Ref cell, IsPrunnedFunction is_prunned); static Ref generate_raw(Ref cell, CellUsageTree *usage_tree); static Ref virtualize_raw(Ref cell, Cell::VirtualizationParameters virt); + static Ref combine_raw(Ref a, Ref b); + static Ref combine_fast_raw(Ref a, Ref b); }; class MerkleProofBuilder { diff --git a/submodules/ton/tonlib-src/crypto/vm/cells/MerkleUpdate.cpp b/submodules/ton/tonlib-src/crypto/vm/cells/MerkleUpdate.cpp index 30b5116ecf..d75f16675e 100644 --- a/submodules/ton/tonlib-src/crypto/vm/cells/MerkleUpdate.cpp +++ b/submodules/ton/tonlib-src/crypto/vm/cells/MerkleUpdate.cpp @@ -268,7 +268,7 @@ class MerkleCombine { // 1. Create maximum subtrees of X and Z with all cells in A, B, C and D // Max(V) - such maximum subtree // - // 2. Max(A) and Max(D) should be merkle update already. But win want to minimize it + // 2. Max(A) and Max(D) should be merkle update already. But we want to minimize it // So we cut all branches of Max(D) which are in maxA // When we cut branch q in Max(D) we mark some path to q in Max(A) // Then we cut all branches of Max(A) which are not marked. diff --git a/submodules/ton/tonlib-src/crypto/vm/continuation.cpp b/submodules/ton/tonlib-src/crypto/vm/continuation.cpp index d4952769a5..243dfd5ea0 100644 --- a/submodules/ton/tonlib-src/crypto/vm/continuation.cpp +++ b/submodules/ton/tonlib-src/crypto/vm/continuation.cpp @@ -14,12 +14,14 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "vm/dispatch.h" #include "vm/continuation.h" #include "vm/dict.h" #include "vm/log.h" +#include "vm/vm.h" +#include "vm/vmstate.h" namespace vm { @@ -32,6 +34,17 @@ bool Continuation::has_c0() const { return cont_data && cont_data->save.c[0].not_null(); } +bool ControlRegs::clear() { + for (unsigned i = 0; i < creg_num; i++) { + c[i].clear(); + } + for (unsigned i = 0; i < dreg_num; i++) { + d[i].clear(); + } + c7.clear(); + return true; +} + StackEntry ControlRegs::get(unsigned idx) const { if (idx < creg_num) { return get_c(idx); @@ -107,6 +120,155 @@ ControlRegs& ControlRegs::operator&=(const ControlRegs& save) { return *this; } +bool ControlRegs::serialize(CellBuilder& cb) const { + // _ cregs:(HashmapE 4 VmStackValue) = VmSaveList; + Dictionary dict{4}; + CellBuilder cb2; + for (int i = 0; i < creg_num; i++) { + if (c[i].not_null() && + !(StackEntry{c[i]}.serialize(cb2) && dict.set_builder(td::BitArray<4>(i), cb2) && cb2.reset_bool())) { + return false; + } + } + for (int i = 0; i < dreg_num; i++) { + if (d[i].not_null() && !(StackEntry{d[i]}.serialize(cb2) && dict.set_builder(td::BitArray<4>(dreg_idx + i), cb2) && + cb2.reset_bool())) { + return false; + } + } + return (c7.is_null() || (StackEntry{c7}.serialize(cb2) && dict.set_builder(td::BitArray<4>(7), cb2))) && + std::move(dict).append_dict_to_bool(cb); +} + +bool ControlRegs::deserialize(CellSlice& cs, int mode) { + // _ cregs:(HashmapE 4 VmStackValue) = VmSaveList; + Ref root; + return cs.fetch_maybe_ref(root) && deserialize(std::move(root), mode); +} + +bool ControlRegs::deserialize(Ref root, int mode) { + try { + clear(); + Dictionary dict{std::move(root), 4}; + return dict.check_for_each([this, mode](Ref val, td::ConstBitPtr key, int n) { + StackEntry value; + return value.deserialize(val.write(), mode) && val->empty_ext() && set((int)key.get_uint(4), std::move(value)); + }); + } catch (VmError&) { + return false; + } +} + +bool ControlData::clear() { + stack.clear(); + save.clear(); + nargs = cp = -1; + return true; +} + +bool ControlData::serialize(CellBuilder& cb) const { + // vm_ctl_data$_ nargs:(Maybe uint13) stack:(Maybe VmStack) save:VmSaveList + // cp:(Maybe int16) = VmControlData; + return cb.store_bool_bool(nargs >= 0) // vm_ctl_data$_ nargs:(Maybe ... + && (nargs < 0 || cb.store_long_bool(nargs, 13)) // ... int13) + && cb.store_bool_bool(stack.not_null()) // stack:(Maybe ... + && (stack.is_null() || stack->serialize(cb)) // ... VmStack) + && save.serialize(cb) // save:VmSaveList + && cb.store_bool_bool(cp != -1) // cp:(Maybe ... + && (cp == -1 || cb.store_long_bool(cp, 16)); // ... int16) +} + +bool ControlData::deserialize(CellSlice& cs, int mode) { + // vm_ctl_data$_ nargs:(Maybe uint13) stack:(Maybe VmStack) save:VmSaveList + // cp:(Maybe int16) = VmControlData; + nargs = cp = -1; + stack.clear(); + bool f; + return cs.fetch_bool_to(f) && (!f || cs.fetch_uint_to(13, nargs)) // nargs:(Maybe uint13) + && cs.fetch_bool_to(f) && (!f || Stack::deserialize_to(cs, stack, mode)) // stack:(Maybe VmStack) + && save.deserialize(cs, mode) // save:VmSaveList + && cs.fetch_bool_to(f) && (!f || (cs.fetch_int_to(16, cp) && cp != -1)); // cp:(Maybe int16) +} + +bool Continuation::serialize_ref(CellBuilder& cb) const { + auto* vsi = VmStateInterface::get(); + if (vsi && !vsi->register_op()) { + return false; + } + vm::CellBuilder cb2; + return serialize(cb2) && cb.store_ref_bool(cb2.finalize()); +} + +Ref Continuation::deserialize(CellSlice& cs, int mode) { + if (mode & 0x1002) { + return {}; + } + auto* vsi = VmStateInterface::get(); + if (vsi && !vsi->register_op()) { + return {}; + } + + mode |= 0x1000; + switch (cs.bselect_ext(6, 0x100f011100010001ULL)) { + case 0: + // vmc_std$00 cdata:VmControlData code:VmCellSlice = VmCont; + return OrdCont::deserialize(cs, mode); + case 1: + // vmc_envelope$01 cdata:VmControlData next:^VmCont = VmCont; + return ArgContExt::deserialize(cs, mode); + case 2: + // vmc_quit$1000 exit_code:int32 = VmCont; + return QuitCont::deserialize(cs, mode); + case 3: + // vmc_quit_exc$1001 = VmCont; + return ExcQuitCont::deserialize(cs, mode); + case 4: + // vmc_repeat$10100 count:uint63 body:^VmCont after:^VmCont = VmCont; + return RepeatCont::deserialize(cs, mode); + case 5: + // vmc_until$110000 body:^VmCont after:^VmCont = VmCont; + return UntilCont::deserialize(cs, mode); + case 6: + // vmc_again$110001 body:^VmCont = VmCont; + return AgainCont::deserialize(cs, mode); + case 7: + // vmc_while_cond$110010 cond:^VmCont body:^VmCont after:^VmCont = VmCont; + return WhileCont::deserialize(cs, mode | 0x2000); + case 8: + // vmc_while_body$110011 cond:^VmCont body:^VmCont after:^VmCont = VmCont; + return WhileCont::deserialize(cs, mode & ~0x2000); + case 9: + // vmc_pushint$1111 value:int32 next:^VmCont = VmCont; + return PushIntCont::deserialize(cs, mode); + default: + return {}; + } +} + +bool Continuation::deserialize_to(Ref cell, Ref& cont, int mode) { + if (cell.is_null()) { + cont.clear(); + return false; + } + CellSlice cs = load_cell_slice(std::move(cell)); + return deserialize_to(cs, cont, mode & ~0x1000) && cs.empty_ext(); +} + +bool QuitCont::serialize(CellBuilder& cb) const { + // vmc_quit$1000 exit_code:int32 = VmCont; + return cb.store_long_bool(8, 4) && cb.store_long_bool(exit_code, 32); +} + +Ref QuitCont::deserialize(CellSlice& cs, int mode) { + // vmc_quit$1000 exit_code:int32 = VmCont; + int exit_code; + if (cs.fetch_ulong(4) == 8 && cs.fetch_int_to(32, exit_code)) { + return Ref{true, exit_code}; + } else { + return {}; + } +} + int ExcQuitCont::jump(VmState* st) const & { int n = 0; try { @@ -118,6 +280,16 @@ int ExcQuitCont::jump(VmState* st) const & { return ~n; } +bool ExcQuitCont::serialize(CellBuilder& cb) const { + // vmc_quit_exc$1001 = VmCont; + return cb.store_long_bool(9, 4); +} + +Ref ExcQuitCont::deserialize(CellSlice& cs, int mode) { + // vmc_quit_exc$1001 = VmCont; + return cs.fetch_ulong(4) == 9 ? Ref{true} : Ref{}; +} + int PushIntCont::jump(VmState* st) const & { VM_LOG(st) << "execute implicit PUSH " << push_val << " (slow)"; st->get_stack().push_smallint(push_val); @@ -130,6 +302,24 @@ int PushIntCont::jump_w(VmState* st) & { return st->jump(std::move(next)); } +bool PushIntCont::serialize(CellBuilder& cb) const { + // vmc_pushint$1111 value:int32 next:^VmCont = VmCont; + return cb.store_long_bool(15, 4) && cb.store_long_bool(push_val, 32) && next->serialize_ref(cb); +} + +Ref PushIntCont::deserialize(CellSlice& cs, int mode) { + // vmc_pushint$1111 value:int32 next:^VmCont = VmCont; + int value; + Ref ref; + Ref next; + if (cs.fetch_ulong(4) == 15 && cs.fetch_int_to(32, value) && cs.fetch_ref_to(ref) && + deserialize_to(std::move(ref), next, mode)) { + return Ref{true, value, std::move(next)}; + } else { + return {}; + } +} + int ArgContExt::jump(VmState* st) const & { st->adjust_cr(data.save); if (data.cp != -1) { @@ -146,6 +336,23 @@ int ArgContExt::jump_w(VmState* st) & { return st->jump_to(std::move(ext)); } +bool ArgContExt::serialize(CellBuilder& cb) const { + // vmc_envelope$01 cdata:VmControlData next:^VmCont = VmCont; + return cb.store_long_bool(1, 2) && data.serialize(cb) && ext->serialize_ref(cb); +} + +Ref ArgContExt::deserialize(CellSlice& cs, int mode) { + // vmc_envelope$01 cdata:VmControlData next:^VmCont = VmCont; + ControlData cdata; + Ref ref; + Ref next; + mode &= ~0x1000; + return cs.fetch_ulong(2) == 1 && cdata.deserialize(cs, mode) && cs.fetch_ref_to(ref) && + deserialize_to(std::move(ref), next, mode) + ? Ref{true, std::move(next), std::move(cdata)} + : Ref{}; +} + int RepeatCont::jump(VmState* st) const & { VM_LOG(st) << "repeat " << count << " more times (slow)\n"; if (count <= 0) { @@ -174,6 +381,26 @@ int RepeatCont::jump_w(VmState* st) & { return st->jump(body); } +bool RepeatCont::serialize(CellBuilder& cb) const { + // vmc_repeat$10100 count:uint63 body:^VmCont after:^VmCont = VmCont; + return cb.store_long_bool(0x14, 5) && cb.store_long_bool(count, 63) && body->serialize_ref(cb) && + after->serialize_ref(cb); +} + +Ref RepeatCont::deserialize(CellSlice& cs, int mode) { + // vmc_repeat$10100 count:uint63 body:^VmCont after:^VmCont = VmCont; + long long count; + Ref ref; + Ref body, after; + if (cs.fetch_ulong(5) == 0x14 && cs.fetch_uint_to(63, count) && cs.fetch_ref_to(ref) && + deserialize_to(std::move(ref), body, mode) && cs.fetch_ref_to(ref) && + deserialize_to(std::move(ref), after, mode)) { + return Ref{true, std::move(body), std::move(after), count}; + } else { + return {}; + } +} + int VmState::repeat(Ref body, Ref after, long long count) { if (count <= 0) { body.clear(); @@ -201,6 +428,22 @@ int AgainCont::jump_w(VmState* st) & { } } +bool AgainCont::serialize(CellBuilder& cb) const { + // vmc_again$110001 body:^VmCont = VmCont; + return cb.store_long_bool(0x31, 6) && body->serialize_ref(cb); +} + +Ref AgainCont::deserialize(CellSlice& cs, int mode) { + // vmc_again$110001 body:^VmCont = VmCont; + Ref ref; + Ref body; + if (cs.fetch_ulong(6) == 0x31 && cs.fetch_ref_to(ref) && deserialize_to(std::move(ref), body, mode)) { + return Ref{true, std::move(body)}; + } else { + return {}; + } +} + int VmState::again(Ref body) { return jump(Ref{true, std::move(body)}); } @@ -233,6 +476,23 @@ int UntilCont::jump_w(VmState* st) & { } } +bool UntilCont::serialize(CellBuilder& cb) const { + // vmc_until$110000 body:^VmCont after:^VmCont = VmCont; + return cb.store_long_bool(0x30, 6) && body->serialize_ref(cb) && after->serialize_ref(cb); +} + +Ref UntilCont::deserialize(CellSlice& cs, int mode) { + // vmc_until$110000 body:^VmCont after:^VmCont = VmCont; + Ref ref; + Ref body, after; + if (cs.fetch_ulong(6) == 0x30 && cs.fetch_ref_to(ref) && deserialize_to(std::move(ref), body, mode) && + cs.fetch_ref_to(ref) && deserialize_to(std::move(ref), after, mode)) { + return Ref{true, std::move(body), std::move(after)}; + } else { + return {}; + } +} + int VmState::until(Ref body, Ref after) { if (!body->has_c0()) { set_c0(Ref{true, body, std::move(after)}); @@ -292,6 +552,29 @@ int WhileCont::jump_w(VmState* st) & { } } +bool WhileCont::serialize(CellBuilder& cb) const { + // vmc_while_cond$110010 cond:^VmCont body:^VmCont after:^VmCont = VmCont; + // vmc_while_body$110011 cond:^VmCont body:^VmCont after:^VmCont = VmCont; + return cb.store_long_bool(0x19, 5) && cb.store_bool_bool(!chkcond) && cond->serialize_ref(cb) && + body->serialize_ref(cb) && after->serialize_ref(cb); +} + +Ref WhileCont::deserialize(CellSlice& cs, int mode) { + // vmc_while_cond$110010 cond:^VmCont body:^VmCont after:^VmCont = VmCont; + // vmc_while_body$110011 cond:^VmCont body:^VmCont after:^VmCont = VmCont; + bool at_body; + Ref ref; + Ref cond, body, after; + if (cs.fetch_ulong(5) == 0x19 && cs.fetch_bool_to(at_body) && cs.fetch_ref_to(ref) && + deserialize_to(std::move(ref), cond, mode) && cs.fetch_ref_to(ref) && + deserialize_to(std::move(ref), body, mode) && cs.fetch_ref_to(ref) && + deserialize_to(std::move(ref), after, mode)) { + return Ref{true, std::move(cond), std::move(body), std::move(after), !at_body}; + } else { + return {}; + } +} + int VmState::loop_while(Ref cond, Ref body, Ref after) { if (!cond->has_c0()) { set_c0(Ref{true, cond, std::move(body), std::move(after), true}); @@ -311,6 +594,22 @@ int OrdCont::jump_w(VmState* st) & { return 0; } +bool OrdCont::serialize(CellBuilder& cb) const { + // vmc_std$00 cdata:VmControlData code:VmCellSlice = VmCont; + return cb.store_long_bool(0, 2) && data.serialize(cb) && StackEntry{code}.serialize(cb, 0x1000); +} + +Ref OrdCont::deserialize(CellSlice& cs, int mode) { + // vmc_std$00 cdata:VmControlData code:VmCellSlice = VmCont; + ControlData cdata; + StackEntry val; + mode &= ~0x1000; + return cs.fetch_ulong(2) == 0 && cdata.deserialize(cs, mode) && val.deserialize(cs, 0x4000) && + val.is(StackEntry::t_slice) + ? Ref{true, std::move(val).as_slice(), std::move(cdata)} + : Ref{}; +} + void VmState::init_cregs(bool same_c3, bool push_0) { cr.set_c0(quit0); cr.set_c1(quit1); @@ -337,555 +636,4 @@ void VmState::init_cregs(bool same_c3, bool push_0) { } } -VmState::VmState() : cp(-1), dispatch(&dummy_dispatch_table), quit0(true, 0), quit1(true, 1) { - ensure_throw(init_cp(0)); - init_cregs(); -} - -VmState::VmState(Ref _code) - : code(std::move(_code)), cp(-1), dispatch(&dummy_dispatch_table), quit0(true, 0), quit1(true, 1) { - ensure_throw(init_cp(0)); - init_cregs(); -} - -VmState::VmState(Ref _code, Ref _stack, int flags, Ref _data, VmLog log, - std::vector> _libraries, Ref init_c7) - : code(std::move(_code)) - , stack(std::move(_stack)) - , cp(-1) - , dispatch(&dummy_dispatch_table) - , quit0(true, 0) - , quit1(true, 1) - , log(log) - , libraries(std::move(_libraries)) { - ensure_throw(init_cp(0)); - set_c4(std::move(_data)); - if (init_c7.not_null()) { - set_c7(std::move(init_c7)); - } - init_cregs(flags & 1, flags & 2); -} - -VmState::VmState(Ref _code, Ref _stack, const GasLimits& gas, int flags, Ref _data, VmLog log, - std::vector> _libraries, Ref init_c7) - : code(std::move(_code)) - , stack(std::move(_stack)) - , cp(-1) - , dispatch(&dummy_dispatch_table) - , quit0(true, 0) - , quit1(true, 1) - , log(log) - , gas(gas) - , libraries(std::move(_libraries)) { - ensure_throw(init_cp(0)); - set_c4(std::move(_data)); - if (init_c7.not_null()) { - set_c7(std::move(init_c7)); - } - init_cregs(flags & 1, flags & 2); -} - -Ref VmState::convert_code_cell(Ref code_cell) { - if (code_cell.is_null()) { - return {}; - } - Ref csr{true, NoVmOrd(), code_cell}; - if (csr->is_valid()) { - return csr; - } - return load_cell_slice_ref(CellBuilder{}.store_ref(std::move(code_cell)).finalize()); -} - -bool VmState::init_cp(int new_cp) { - const DispatchTable* dt = DispatchTable::get_table(new_cp); - if (dt) { - cp = new_cp; - dispatch = dt; - return true; - } else { - return false; - } -} - -bool VmState::set_cp(int new_cp) { - return new_cp == cp || init_cp(new_cp); -} - -void VmState::force_cp(int new_cp) { - if (!set_cp(new_cp)) { - throw VmError{Excno::inv_opcode, "unsupported codepage"}; - } -} - -// simple call to a continuation cont -int VmState::call(Ref cont) { - const ControlData* cont_data = cont->get_cdata(); - if (cont_data) { - if (cont_data->save.c[0].not_null()) { - // call reduces to a jump - return jump(std::move(cont)); - } - if (cont_data->stack.not_null() || cont_data->nargs >= 0) { - // if cont has non-empty stack or expects fixed number of arguments, call is not simple - return call(std::move(cont), -1, -1); - } - // create return continuation, to be stored into new c0 - Ref ret = Ref{true, std::move(code), cp}; - ret.unique_write().get_cdata()->save.set_c0(std::move(cr.c[0])); - cr.set_c0( - std::move(ret)); // set c0 to its final value before switching to cont; notice that cont.save.c0 is not set - return jump_to(std::move(cont)); - } - // create return continuation, to be stored into new c0 - Ref ret = Ref{true, std::move(code), cp}; - ret.unique_write().get_cdata()->save.set_c0(std::move(cr.c[0])); - // general implementation of a simple call - cr.set_c0(std::move(ret)); // set c0 to its final value before switching to cont; notice that cont.save.c0 is not set - return jump_to(std::move(cont)); -} - -// call with parameters to continuation cont -int VmState::call(Ref cont, int pass_args, int ret_args) { - const ControlData* cont_data = cont->get_cdata(); - if (cont_data) { - if (cont_data->save.c[0].not_null()) { - // call reduces to a jump - return jump(std::move(cont), pass_args); - } - int depth = stack->depth(); - if (pass_args > depth || cont_data->nargs > depth) { - throw VmError{Excno::stk_und, "stack underflow while calling a continuation: not enough arguments on stack"}; - } - if (cont_data->nargs > pass_args && pass_args >= 0) { - throw VmError{Excno::stk_und, - "stack underflow while calling a closure continuation: not enough arguments passed"}; - } - auto old_c0 = std::move(cr.c[0]); - // optimization(?): decrease refcnts of unused continuations in c[i] as early as possible - preclear_cr(cont_data->save); - // no exceptions should be thrown after this point - int copy = cont_data->nargs, skip = 0; - if (pass_args >= 0) { - if (copy >= 0) { - skip = pass_args - copy; - } else { - copy = pass_args; - } - } - // copy=-1 : pass whole stack, else pass top `copy` elements, drop next `skip` elements. - Ref new_stk; - if (cont_data->stack.not_null() && !cont_data->stack->is_empty()) { - // `cont` already has a stack, create resulting stack from it - if (copy < 0) { - copy = stack->depth(); - } - if (cont->is_unique()) { - // optimization: avoid copying stack if we hold the only copy of `cont` - new_stk = std::move(cont.unique_write().get_cdata()->stack); - } else { - new_stk = cont_data->stack; - } - new_stk.write().move_from_stack(get_stack(), copy); - if (skip > 0) { - get_stack().pop_many(skip); - } - } else if (copy >= 0) { - new_stk = get_stack().split_top(copy, skip); - } else { - new_stk = std::move(stack); - stack.clear(); - } - // create return continuation using the remainder of current stack - Ref ret = Ref{true, std::move(code), cp, std::move(stack), ret_args}; - ret.unique_write().get_cdata()->save.set_c0(std::move(old_c0)); - Ref ord_cont = static_cast>(cont); - set_stack(std::move(new_stk)); - cr.set_c0(std::move(ret)); // ??? if codepage of code in ord_cont is unknown, will end up with incorrect c0 - return jump_to(std::move(cont)); - } else { - // have no continuation data, situation is somewhat simpler - int depth = stack->depth(); - if (pass_args > depth) { - throw VmError{Excno::stk_und, "stack underflow while calling a continuation: not enough arguments on stack"}; - } - // create new stack from the top `pass_args` elements of the current stack - Ref new_stk = (pass_args >= 0 ? get_stack().split_top(pass_args) : std::move(stack)); - // create return continuation using the remainder of the current stack - Ref ret = Ref{true, std::move(code), cp, std::move(stack), ret_args}; - ret.unique_write().get_cdata()->save.set_c0(std::move(cr.c[0])); - set_stack(std::move(new_stk)); - cr.set_c0(std::move(ret)); // ??? if codepage of code in ord_cont is unknown, will end up with incorrect c0 - return jump_to(std::move(cont)); - } -} - -// simple jump to continuation cont -int VmState::jump(Ref cont) { - const ControlData* cont_data = cont->get_cdata(); - if (cont_data && (cont_data->stack.not_null() || cont_data->nargs >= 0)) { - // if cont has non-empty stack or expects fixed number of arguments, jump is not simple - return jump(std::move(cont), -1); - } else { - return jump_to(std::move(cont)); - } -} - -// general jump to continuation cont -int VmState::jump(Ref cont, int pass_args) { - const ControlData* cont_data = cont->get_cdata(); - if (cont_data) { - // first do the checks - int depth = stack->depth(); - if (pass_args > depth || cont_data->nargs > depth) { - throw VmError{Excno::stk_und, "stack underflow while jumping to a continuation: not enough arguments on stack"}; - } - if (cont_data->nargs > pass_args && pass_args >= 0) { - throw VmError{Excno::stk_und, - "stack underflow while jumping to closure continuation: not enough arguments passed"}; - } - // optimization(?): decrease refcnts of unused continuations in c[i] as early as possible - preclear_cr(cont_data->save); - // no exceptions should be thrown after this point - int copy = cont_data->nargs; - if (pass_args >= 0 && copy < 0) { - copy = pass_args; - } - // copy=-1 : pass whole stack, else pass top `copy` elements, drop the remainder. - if (cont_data->stack.not_null() && !cont_data->stack->is_empty()) { - // `cont` already has a stack, create resulting stack from it - if (copy < 0) { - copy = get_stack().depth(); - } - Ref new_stk; - if (cont->is_unique()) { - // optimization: avoid copying the stack if we hold the only copy of `cont` - new_stk = std::move(cont.unique_write().get_cdata()->stack); - } else { - new_stk = cont_data->stack; - } - new_stk.write().move_from_stack(get_stack(), copy); - set_stack(std::move(new_stk)); - } else { - if (copy >= 0) { - get_stack().drop_bottom(stack->depth() - copy); - } - } - return jump_to(std::move(cont)); - } else { - // have no continuation data, situation is somewhat simpler - if (pass_args >= 0) { - int depth = get_stack().depth(); - if (pass_args > depth) { - throw VmError{Excno::stk_und, "stack underflow while jumping to a continuation: not enough arguments on stack"}; - } - get_stack().drop_bottom(depth - pass_args); - } - return jump_to(std::move(cont)); - } -} - -int VmState::ret() { - Ref cont = quit0; - cont.swap(cr.c[0]); - return jump(std::move(cont)); -} - -int VmState::ret(int ret_args) { - Ref cont = quit0; - cont.swap(cr.c[0]); - return jump(std::move(cont), ret_args); -} - -int VmState::ret_alt() { - Ref cont = quit1; - cont.swap(cr.c[1]); - return jump(std::move(cont)); -} - -int VmState::ret_alt(int ret_args) { - Ref cont = quit1; - cont.swap(cr.c[1]); - return jump(std::move(cont), ret_args); -} - -Ref VmState::extract_cc(int save_cr, int stack_copy, int cc_args) { - Ref new_stk; - if (stack_copy < 0 || stack_copy == stack->depth()) { - new_stk = std::move(stack); - stack.clear(); - } else if (stack_copy > 0) { - stack->check_underflow(stack_copy); - new_stk = get_stack().split_top(stack_copy); - } else { - new_stk = Ref{true}; - } - Ref cc = Ref{true, std::move(code), cp, std::move(stack), cc_args}; - stack = std::move(new_stk); - if (save_cr & 7) { - ControlData* cdata = cc.unique_write().get_cdata(); - if (save_cr & 1) { - cdata->save.set_c0(std::move(cr.c[0])); - cr.set_c0(quit0); - } - if (save_cr & 2) { - cdata->save.set_c1(std::move(cr.c[1])); - cr.set_c1(quit1); - } - if (save_cr & 4) { - cdata->save.set_c2(std::move(cr.c[2])); - // cr.set_c2(Ref{true}); - } - } - return cc; -} - -int VmState::throw_exception(int excno) { - Stack& stack_ref = get_stack(); - stack_ref.clear(); - stack_ref.push_smallint(0); - stack_ref.push_smallint(excno); - code.clear(); - consume_gas(exception_gas_price); - return jump(get_c2()); -} - -int VmState::throw_exception(int excno, StackEntry&& arg) { - Stack& stack_ref = get_stack(); - stack_ref.clear(); - stack_ref.push(std::move(arg)); - stack_ref.push_smallint(excno); - code.clear(); - consume_gas(exception_gas_price); - return jump(get_c2()); -} - -void GasLimits::gas_exception() const { - throw VmNoGas{}; -} - -void GasLimits::set_limits(long long _max, long long _limit, long long _credit) { - gas_max = _max; - gas_limit = _limit; - gas_credit = _credit; - change_base(_limit + _credit); -} - -void GasLimits::change_limit(long long _limit) { - _limit = std::min(std::max(_limit, 0LL), gas_max); - gas_credit = 0; - gas_limit = _limit; - change_base(_limit); -} - -bool VmState::set_gas_limits(long long _max, long long _limit, long long _credit) { - gas.set_limits(_max, _limit, _credit); - return true; -} - -void VmState::change_gas_limit(long long new_limit) { - VM_LOG(this) << "changing gas limit to " << std::min(new_limit, gas.gas_max); - gas.change_limit(new_limit); -} - -int VmState::step() { - assert(!code.is_null()); - //VM_LOG(st) << "stack:"; stack->dump(VM_LOG(st)); - //VM_LOG(st) << "; cr0.refcnt = " << get_c0()->get_refcnt() - 1 << std::endl; - if (stack_trace) { - stack->dump(std::cerr); - } - ++steps; - if (code->size()) { - return dispatch->dispatch(this, code.write()); - } else if (code->size_refs()) { - VM_LOG(this) << "execute implicit JMPREF\n"; - Ref cont = Ref{true, load_cell_slice_ref(code->prefetch_ref()), get_cp()}; - return jump(std::move(cont)); - } else { - VM_LOG(this) << "execute implicit RET\n"; - return ret(); - } -} - -int VmState::run() { - int res; - Guard guard(this); - do { - // LOG(INFO) << "[BS] data cells: " << DataCell::get_total_data_cells(); - try { - try { - res = step(); - gas.check(); - } catch (vm::CellBuilder::CellWriteError) { - throw VmError{Excno::cell_ov}; - } catch (vm::CellBuilder::CellCreateError) { - throw VmError{Excno::cell_ov}; - } catch (vm::CellSlice::CellReadError) { - throw VmError{Excno::cell_und}; - } - } catch (const VmError& vme) { - VM_LOG(this) << "handling exception code " << vme.get_errno() << ": " << vme.get_msg(); - try { - // LOG(INFO) << "[EX] data cells: " << DataCell::get_total_data_cells(); - ++steps; - res = throw_exception(vme.get_errno()); - } catch (const VmError& vme2) { - VM_LOG(this) << "exception " << vme2.get_errno() << " while handling exception: " << vme.get_msg(); - // LOG(INFO) << "[EXX] data cells: " << DataCell::get_total_data_cells(); - return ~vme2.get_errno(); - } - } catch (VmNoGas vmoog) { - ++steps; - VM_LOG(this) << "unhandled out-of-gas exception: gas consumed=" << gas.gas_consumed() - << ", limit=" << gas.gas_limit; - get_stack().clear(); - get_stack().push_smallint(gas.gas_consumed()); - return vmoog.get_errno(); // no ~ for unhandled exceptions (to make their faking impossible) - } - } while (!res); - // LOG(INFO) << "[EN] data cells: " << DataCell::get_total_data_cells(); - if ((res | 1) == -1) { - commit(); - } - return res; -} - -ControlData* force_cdata(Ref& cont) { - if (!cont->get_cdata()) { - cont = Ref{true, cont}; - return cont.unique_write().get_cdata(); - } else { - return cont.write().get_cdata(); - } -} - -ControlRegs* force_cregs(Ref& cont) { - return &force_cdata(cont)->save; -} - -int run_vm_code(Ref code, Ref& stack, int flags, Ref* data_ptr, VmLog log, long long* steps, - GasLimits* gas_limits, std::vector> libraries, Ref init_c7) { - VmState vm{code, - std::move(stack), - gas_limits ? *gas_limits : GasLimits{}, - flags, - data_ptr ? *data_ptr : Ref{}, - log, - std::move(libraries), - std::move(init_c7)}; - int res = vm.run(); - stack = vm.get_stack_ref(); - if (res == -1 && data_ptr) { - *data_ptr = vm.get_c4(); - } - if (steps) { - *steps = vm.get_steps_count(); - } - if (gas_limits) { - *gas_limits = vm.get_gas_limits(); - LOG(INFO) << "steps: " << vm.get_steps_count() << " gas: used=" << gas_limits->gas_consumed() - << ", max=" << gas_limits->gas_max << ", limit=" << gas_limits->gas_limit - << ", credit=" << gas_limits->gas_credit; - } - if ((vm.get_log().log_mask & vm::VmLog::DumpStack) != 0) { - VM_LOG(&vm) << "BEGIN_STACK_DUMP"; - for (int i = stack->depth(); i > 0; i--) { - VM_LOG(&vm) << (*stack)[i - 1].to_string(); - } - VM_LOG(&vm) << "END_STACK_DUMP"; - } - - return ~res; -} - -int run_vm_code(Ref code, Stack& stack, int flags, Ref* data_ptr, VmLog log, long long* steps, - GasLimits* gas_limits, std::vector> libraries, Ref init_c7) { - Ref stk{true}; - stk.unique_write().set_contents(std::move(stack)); - stack.clear(); - int res = run_vm_code(code, stk, flags, data_ptr, log, steps, gas_limits, std::move(libraries), std::move(init_c7)); - CHECK(stack.is_unique()); - if (stk.is_null()) { - stack.clear(); - } else if (&(*stk) != &stack) { - VmState* st = nullptr; - if (stk->is_unique()) { - VM_LOG(st) << "move resulting stack (" << stk->depth() << " entries)"; - stack.set_contents(std::move(stk.unique_write())); - } else { - VM_LOG(st) << "copying resulting stack (" << stk->depth() << " entries)"; - stack.set_contents(*stk); - } - } - return res; -} - -// may throw a dictionary exception; returns nullptr if library is not found in context -Ref VmState::load_library(td::ConstBitPtr hash) { - std::unique_ptr tmp_ctx; - // install temporary dummy vm state interface to prevent charging for cell load operations during library lookup - VmStateInterface::Guard(tmp_ctx.get()); - for (const auto& lib_collection : libraries) { - auto lib = lookup_library_in(hash, lib_collection); - if (lib.not_null()) { - return lib; - } - } - return {}; -} - -bool VmState::register_library_collection(Ref lib) { - if (lib.is_null()) { - return true; - } - libraries.push_back(std::move(lib)); - return true; -} - -void VmState::register_cell_load() { - consume_gas(cell_load_gas_price); -} - -void VmState::register_cell_create() { - consume_gas(cell_create_gas_price); -} - -td::BitArray<256> VmState::get_state_hash() const { - // TODO: implement properly, by serializing the stack etc, and computing the Merkle hash - td::BitArray<256> res; - res.clear(); - return res; -} - -td::BitArray<256> VmState::get_final_state_hash(int exit_code) const { - // TODO: implement properly, by serializing the stack etc, and computing the Merkle hash - td::BitArray<256> res; - res.clear(); - return res; -} - -Ref lookup_library_in(td::ConstBitPtr key, vm::Dictionary& dict) { - try { - auto val = dict.lookup(key, 256); - if (val.is_null() || !val->have_refs()) { - return {}; - } - auto root = val->prefetch_ref(); - if (root.not_null() && !root->get_hash().bits().compare(key, 256)) { - return root; - } - return {}; - } catch (vm::VmError) { - return {}; - } -} - -Ref lookup_library_in(td::ConstBitPtr key, Ref lib_root) { - if (lib_root.is_null()) { - return lib_root; - } - vm::Dictionary dict{std::move(lib_root), 256}; - return lookup_library_in(key, dict); -} - } // namespace vm diff --git a/submodules/ton/tonlib-src/crypto/vm/continuation.h b/submodules/ton/tonlib-src/crypto/vm/continuation.h index c6c9d320ed..37abe86996 100644 --- a/submodules/ton/tonlib-src/crypto/vm/continuation.h +++ b/submodules/ton/tonlib-src/crypto/vm/continuation.h @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once @@ -37,6 +37,7 @@ struct ControlRegs { Ref c[creg_num]; // c0..c3 Ref d[dreg_num]; // c4..c5 Ref c7; // c7 + bool clear(); Ref get_c(unsigned idx) const { return idx < creg_num ? c[idx] : Ref{}; } @@ -135,6 +136,9 @@ struct ControlRegs { ControlRegs& operator&=(const ControlRegs& save); // clears all c[i]'s which are present in save ControlRegs& operator^=(const ControlRegs& save); // sets c[i]=save.c[i] for all save.c[i] != 0 ControlRegs& operator^=(ControlRegs&& save); + bool serialize(CellBuilder& cb) const; + bool deserialize(CellSlice& cs, int mode = 0); + bool deserialize(Ref root, int mode = 0); }; struct ControlData { @@ -150,11 +154,14 @@ struct ControlData { } ControlData(int _cp, Ref _stack, int _nargs = -1) : stack(std::move(_stack)), nargs(_nargs), cp(_cp) { } + bool clear(); + bool serialize(CellBuilder& cb) const; + bool deserialize(CellSlice& cs, int mode = 0); }; class Continuation : public td::CntObject { public: - virtual int jump(VmState* st) const& = 0; + virtual int jump(VmState* st) const & = 0; virtual int jump_w(VmState* st) &; virtual ControlData* get_cdata() { return 0; @@ -175,6 +182,15 @@ class Continuation : public td::CntObject { return *this; } ~Continuation() override = default; + virtual bool serialize(CellBuilder& cb) const { + return false; + } + bool serialize_ref(CellBuilder& cb) const; + static Ref deserialize(CellSlice& cs, int mode = 0); + static bool deserialize_to(CellSlice& cs, Ref& cont, int mode = 0) { + return (cont = deserialize(cs, mode)).not_null(); + } + static bool deserialize_to(Ref cell, Ref& cont, int mode = 0); }; class QuitCont : public Continuation { @@ -184,16 +200,20 @@ class QuitCont : public Continuation { QuitCont(int _code = 0) : exit_code(_code) { } ~QuitCont() override = default; - int jump(VmState* st) const& override { + int jump(VmState* st) const & override { return ~exit_code; } + bool serialize(CellBuilder& cb) const override; + static Ref deserialize(CellSlice& cs, int mode = 0); }; class ExcQuitCont : public Continuation { public: ExcQuitCont() = default; ~ExcQuitCont() override = default; - int jump(VmState* st) const& override; + int jump(VmState* st) const & override; + bool serialize(CellBuilder& cb) const override; + static Ref deserialize(CellSlice& cs, int mode = 0); }; class PushIntCont : public Continuation { @@ -204,8 +224,10 @@ class PushIntCont : public Continuation { PushIntCont(int val, Ref _next) : push_val(val), next(_next) { } ~PushIntCont() override = default; - int jump(VmState* st) const& override; + int jump(VmState* st) const & override; int jump_w(VmState* st) & override; + bool serialize(CellBuilder& cb) const override; + static Ref deserialize(CellSlice& cs, int mode = 0); }; class RepeatCont : public Continuation { @@ -217,8 +239,10 @@ class RepeatCont : public Continuation { : body(std::move(_body)), after(std::move(_after)), count(_count) { } ~RepeatCont() override = default; - int jump(VmState* st) const& override; + int jump(VmState* st) const & override; int jump_w(VmState* st) & override; + bool serialize(CellBuilder& cb) const override; + static Ref deserialize(CellSlice& cs, int mode = 0); }; class AgainCont : public Continuation { @@ -228,8 +252,10 @@ class AgainCont : public Continuation { AgainCont(Ref _body) : body(std::move(_body)) { } ~AgainCont() override = default; - int jump(VmState* st) const& override; + int jump(VmState* st) const & override; int jump_w(VmState* st) & override; + bool serialize(CellBuilder& cb) const override; + static Ref deserialize(CellSlice& cs, int mode = 0); }; class UntilCont : public Continuation { @@ -239,8 +265,10 @@ class UntilCont : public Continuation { UntilCont(Ref _body, Ref _after) : body(std::move(_body)), after(std::move(_after)) { } ~UntilCont() override = default; - int jump(VmState* st) const& override; + int jump(VmState* st) const & override; int jump_w(VmState* st) & override; + bool serialize(CellBuilder& cb) const override; + static Ref deserialize(CellSlice& cs, int mode = 0); }; class WhileCont : public Continuation { @@ -252,8 +280,10 @@ class WhileCont : public Continuation { : cond(std::move(_cond)), body(std::move(_body)), after(std::move(_after)), chkcond(_chk) { } ~WhileCont() override = default; - int jump(VmState* st) const& override; + int jump(VmState* st) const & override; int jump_w(VmState* st) & override; + bool serialize(CellBuilder& cb) const override; + static Ref deserialize(CellSlice& cs, int mode = 0); }; class ArgContExt : public Continuation { @@ -261,14 +291,18 @@ class ArgContExt : public Continuation { Ref ext; public: - ArgContExt(Ref _ext) : data(), ext(_ext) { + ArgContExt(Ref _ext) : data(), ext(std::move(_ext)) { } - ArgContExt(Ref _ext, Ref _stack) : data(_stack), ext(_ext) { + ArgContExt(Ref _ext, Ref _stack) : data(std::move(_stack)), ext(std::move(_ext)) { + } + ArgContExt(Ref _ext, const ControlData& _cdata) : data(_cdata), ext(std::move(_ext)) { + } + ArgContExt(Ref _ext, ControlData&& _cdata) : data(std::move(_cdata)), ext(std::move(_ext)) { } ArgContExt(const ArgContExt&) = default; ArgContExt(ArgContExt&&) = default; ~ArgContExt() override = default; - int jump(VmState* st) const& override; + int jump(VmState* st) const & override; int jump_w(VmState* st) & override; ControlData* get_cdata() override { return &data; @@ -279,6 +313,8 @@ class ArgContExt : public Continuation { td::CntObject* make_copy() const override { return new ArgContExt{*this}; } + bool serialize(CellBuilder& cb) const override; + static Ref deserialize(CellSlice& cs, int mode = 0); }; class OrdCont : public Continuation { @@ -296,6 +332,10 @@ class OrdCont : public Continuation { OrdCont(Ref _code, int _cp, Ref _stack, int nargs = -1) : data(_cp, std::move(_stack), nargs), code(std::move(_code)) { } + OrdCont(Ref _code, const ControlData& _cdata) : data(_cdata), code(std::move(_code)) { + } + OrdCont(Ref _code, ControlData&& _cdata) : data(std::move(_cdata)), code(std::move(_code)) { + } OrdCont(const OrdCont&) = default; OrdCont(OrdCont&&) = default; ~OrdCont() override = default; @@ -303,7 +343,7 @@ class OrdCont : public Continuation { td::CntObject* make_copy() const override { return new OrdCont{*this}; } - int jump(VmState* st) const& override; + int jump(VmState* st) const & override; int jump_w(VmState* st) & override; ControlData* get_cdata() override { @@ -321,297 +361,17 @@ class OrdCont : public Continuation { Ref get_stack_ref() const { return data.stack; } - Ref copy_ord() const& { + Ref copy_ord() const & { return Ref{true, *this}; } Ref copy_ord() && { return Ref{true, *this}; } + bool serialize(CellBuilder& cb) const override; + static Ref deserialize(CellSlice& cs, int mode = 0); }; -struct GasLimits { - static constexpr long long infty = (1ULL << 63) - 1; - long long gas_max, gas_limit, gas_credit, gas_remaining, gas_base; - GasLimits() : gas_max(infty), gas_limit(infty), gas_credit(0), gas_remaining(infty), gas_base(infty) { - } - GasLimits(long long _limit, long long _max = infty, long long _credit = 0) - : gas_max(_max) - , gas_limit(_limit) - , gas_credit(_credit) - , gas_remaining(_limit + _credit) - , gas_base(gas_remaining) { - } - long long gas_consumed() const { - return gas_base - gas_remaining; - } - void set_limits(long long _max, long long _limit, long long _credit = 0); - void change_base(long long _base) { - gas_remaining += _base - gas_base; - gas_base = _base; - } - void change_limit(long long _limit); - void consume(long long amount) { - // LOG(DEBUG) << "consume " << amount << " gas (" << gas_remaining << " remaining)"; - gas_remaining -= amount; - } - bool try_consume(long long amount) { - // LOG(DEBUG) << "try consume " << amount << " gas (" << gas_remaining << " remaining)"; - return (gas_remaining -= amount) >= 0; - } - void gas_exception() const; - void gas_exception(bool cond) const { - if (!cond) { - gas_exception(); - } - } - void consume_chk(long long amount) { - gas_exception(try_consume(amount)); - } - void check() const { - gas_exception(gas_remaining >= 0); - } - bool final_ok() const { - return gas_remaining >= gas_credit; - } -}; - -struct CommittedState { - Ref c4, c5; - bool committed{false}; -}; - -class VmState final : public VmStateInterface { - Ref code; - Ref stack; - ControlRegs cr; - CommittedState cstate; - int cp; - long long steps{0}; - const DispatchTable* dispatch; - Ref quit0, quit1; - VmLog log; - GasLimits gas; - std::vector> libraries; - int stack_trace{0}, debug_off{0}; - - bool chksig_always_succeed{false}; - - public: - static constexpr unsigned cell_load_gas_price = 100, cell_create_gas_price = 500, exception_gas_price = 50, - tuple_entry_gas_price = 1; - VmState(); - VmState(Ref _code); - VmState(Ref _code, Ref _stack, int flags = 0, Ref _data = {}, VmLog log = {}, - std::vector> _libraries = {}, Ref init_c7 = {}); - VmState(Ref _code, Ref _stack, const GasLimits& _gas, int flags = 0, Ref _data = {}, - VmLog log = {}, std::vector> _libraries = {}, Ref init_c7 = {}); - template - VmState(Ref code_cell, Args&&... args) - : VmState(convert_code_cell(std::move(code_cell)), std::forward(args)...) { - } - VmState(const VmState&) = delete; - VmState(VmState&&) = delete; - VmState& operator=(const VmState&) = delete; - VmState& operator=(VmState&&) = delete; - bool set_gas_limits(long long _max, long long _limit, long long _credit = 0); - bool final_gas_ok() const { - return gas.final_ok(); - } - long long gas_consumed() const { - return gas.gas_consumed(); - } - bool committed() const { - return cstate.committed; - } - const CommittedState& get_committed_state() const { - return cstate; - } - void consume_gas(long long amount) { - gas.consume(amount); - } - void consume_tuple_gas(unsigned tuple_len) { - consume_gas(tuple_len * tuple_entry_gas_price); - } - void consume_tuple_gas(const Ref& tup) { - if (tup.not_null()) { - consume_tuple_gas((unsigned)tup->size()); - } - } - GasLimits get_gas_limits() const { - return gas; - } - void change_gas_limit(long long new_limit); - template - void check_underflow(Args... args) { - stack->check_underflow(args...); - } - bool register_library_collection(Ref lib); - Ref load_library( - td::ConstBitPtr hash) override; // may throw a dictionary exception; returns nullptr if library is not found - void register_cell_load() override; - void register_cell_create() override; - bool init_cp(int new_cp); - bool set_cp(int new_cp); - void force_cp(int new_cp); - int get_cp() const { - return cp; - } - int incr_stack_trace(int v) { - return stack_trace += v; - } - long long get_steps_count() const { - return steps; - } - td::BitArray<256> get_state_hash() const; - td::BitArray<256> get_final_state_hash(int exit_code) const; - int step(); - int run(); - Stack& get_stack() { - return stack.write(); - } - const Stack& get_stack_const() const { - return *stack; - } - Ref get_stack_ref() const { - return stack; - } - Ref get_c0() const { - return cr.c[0]; - } - Ref get_c1() const { - return cr.c[1]; - } - Ref get_c2() const { - return cr.c[2]; - } - Ref get_c3() const { - return cr.c[3]; - } - Ref get_c4() const { - return cr.d[0]; - } - Ref get_c7() const { - return cr.c7; - } - Ref get_c(unsigned idx) const { - return cr.get_c(idx); - } - Ref get_d(unsigned idx) const { - return cr.get_d(idx); - } - StackEntry get(unsigned idx) const { - return cr.get(idx); - } - const VmLog& get_log() const { - return log; - } - void define_c0(Ref cont) { - cr.define_c0(std::move(cont)); - } - void set_c0(Ref cont) { - cr.set_c0(std::move(cont)); - } - void set_c1(Ref cont) { - cr.set_c1(std::move(cont)); - } - void set_c2(Ref cont) { - cr.set_c2(std::move(cont)); - } - bool set_c(unsigned idx, Ref val) { - return cr.set_c(idx, std::move(val)); - } - bool set_d(unsigned idx, Ref val) { - return cr.set_d(idx, std::move(val)); - } - void set_c4(Ref val) { - cr.set_c4(std::move(val)); - } - bool set_c7(Ref val) { - return cr.set_c7(std::move(val)); - } - bool set(unsigned idx, StackEntry val) { - return cr.set(idx, std::move(val)); - } - void set_stack(Ref new_stk) { - stack = std::move(new_stk); - } - Ref swap_stack(Ref new_stk) { - stack.swap(new_stk); - return new_stk; - } - void ensure_throw(bool cond) const { - if (!cond) { - fatal(); - } - } - void set_code(Ref _code, int _cp) { - code = std::move(_code); - force_cp(_cp); - } - Ref get_code() const { - return code; - } - void push_code() { - get_stack().push_cellslice(get_code()); - } - void adjust_cr(const ControlRegs& save) { - cr ^= save; - } - void adjust_cr(ControlRegs&& save) { - cr ^= save; - } - void preclear_cr(const ControlRegs& save) { - cr &= save; - } - int call(Ref cont); - int call(Ref cont, int pass_args, int ret_args = -1); - int jump(Ref cont); - int jump(Ref cont, int pass_args); - int ret(); - int ret(int ret_args); - int ret_alt(); - int ret_alt(int ret_args); - int repeat(Ref body, Ref after, long long count); - int again(Ref body); - int until(Ref body, Ref after); - int loop_while(Ref cond, Ref body, Ref after); - int throw_exception(int excno, StackEntry&& arg); - int throw_exception(int excno); - Ref extract_cc(int save_cr = 1, int stack_copy = -1, int cc_args = -1); - void fatal(void) const { - throw VmFatal{}; - } - int jump_to(Ref cont) { - return cont->is_unique() ? cont.unique_write().jump_w(this) : cont->jump(this); - } - static Ref convert_code_cell(Ref code_cell); - void commit() { - cstate.c4 = cr.d[0]; - cstate.c5 = cr.d[1]; - cstate.committed = true; - } - - void set_chksig_always_succeed(bool flag) { - chksig_always_succeed = flag; - } - bool get_chksig_always_succeed() const { - return chksig_always_succeed; - } - - private: - void init_cregs(bool same_c3 = false, bool push_0 = true); -}; - -int run_vm_code(Ref _code, Ref& _stack, int flags = 0, Ref* data_ptr = 0, VmLog log = {}, - long long* steps = nullptr, GasLimits* gas_limits = nullptr, std::vector> libraries = {}, - Ref init_c7 = {}); -int run_vm_code(Ref _code, Stack& _stack, int flags = 0, Ref* data_ptr = 0, VmLog log = {}, - long long* steps = nullptr, GasLimits* gas_limits = nullptr, std::vector> libraries = {}, - Ref init_c7 = {}); - ControlData* force_cdata(Ref& cont); ControlRegs* force_cregs(Ref& cont); -Ref lookup_library_in(td::ConstBitPtr key, Ref lib_root); - } // namespace vm diff --git a/submodules/ton/tonlib-src/crypto/vm/contops.cpp b/submodules/ton/tonlib-src/crypto/vm/contops.cpp index 0039439e6b..63d5570539 100644 --- a/submodules/ton/tonlib-src/crypto/vm/contops.cpp +++ b/submodules/ton/tonlib-src/crypto/vm/contops.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include #include "vm/contops.h" @@ -24,6 +24,7 @@ #include "vm/continuation.h" #include "vm/cellops.h" #include "vm/excno.hpp" +#include "vm/vm.h" namespace vm { @@ -626,9 +627,23 @@ inline void throw_rangechk(bool ok) { } } // namespace +int exec_bless_pop_c3(VmState* st) { + Stack& stack = st->get_stack(); + VM_LOG(st) << "execute CTOSBLESSPOPc3"; + stack.check_underflow(1); + throw_typechk(st->set_c(3, Ref{true, vm::load_cell_slice_ref(stack.pop_cell()), st->get_cp()})); + return 0; +} + int exec_pop_ctr(VmState* st, unsigned args) { unsigned idx = args & 15; VM_LOG(st) << "execute POP c" << idx; + /* + if (idx == 3 && st->get_stack().depth() > 0 && st->get_stack().tos().is(StackEntry::t_cell)) { + // temp hack: accept cell argument for POP c3 and do auto-BLESSing + return exec_bless_pop_c3(st); + } + */ throw_typechk(st->set(idx, st->get_stack().pop_chk())); return 0; } diff --git a/submodules/ton/tonlib-src/crypto/vm/cp0.cpp b/submodules/ton/tonlib-src/crypto/vm/cp0.cpp index 3e062140f2..fe5dd8ef1f 100644 --- a/submodules/ton/tonlib-src/crypto/vm/cp0.cpp +++ b/submodules/ton/tonlib-src/crypto/vm/cp0.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "cp0.h" #include "opctable.h" @@ -29,7 +29,8 @@ namespace vm { -const OpcodeTable* init_op_cp0() { +const OpcodeTable* init_op_cp0(bool enable_debug) { + set_debug_enabled(enable_debug); static const OpcodeTable* static_op_cp0 = [] { auto op_cp0 = new OpcodeTable("TEST CODEPAGE", Codepage::test_cp); register_stack_ops(*op_cp0); // stackops.cpp diff --git a/submodules/ton/tonlib-src/crypto/vm/cp0.h b/submodules/ton/tonlib-src/crypto/vm/cp0.h index 34fc971142..9a6579697d 100644 --- a/submodules/ton/tonlib-src/crypto/vm/cp0.h +++ b/submodules/ton/tonlib-src/crypto/vm/cp0.h @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once #include "vm/dispatch.h" @@ -23,6 +23,6 @@ namespace vm { class OpcodeTable; -const OpcodeTable* init_op_cp0(); +const OpcodeTable* init_op_cp0(bool debug_enabled = false); } // namespace vm diff --git a/submodules/ton/tonlib-src/crypto/vm/debugops.cpp b/submodules/ton/tonlib-src/crypto/vm/debugops.cpp index 911d6313b8..0ec205a315 100644 --- a/submodules/ton/tonlib-src/crypto/vm/debugops.cpp +++ b/submodules/ton/tonlib-src/crypto/vm/debugops.cpp @@ -14,19 +14,23 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include #include "vm/debugops.h" #include "vm/log.h" #include "vm/opctable.h" #include "vm/stack.hpp" -#include "vm/continuation.h" #include "vm/excno.hpp" +#include "vm/vm.h" namespace vm { -bool vm_debug_enabled = true; +bool vm_debug_enabled = false; + +void set_debug_enabled(bool enable_debug) { + vm_debug_enabled = enable_debug; +} int exec_dummy_debug(VmState* st, int args) { VM_LOG(st) << "execute DEBUG " << (args & 0xff); @@ -66,6 +70,9 @@ int compute_len_debug_str(const CellSlice& cs, unsigned args, int pfx_bits) { int exec_dump_stack(VmState* st) { VM_LOG(st) << "execute DUMPSTK"; + if (!vm_debug_enabled) { + return 0; + } Stack& stack = st->get_stack(); int d = stack.depth(); std::cerr << "#DEBUG#: stack(" << d << " values) : "; @@ -74,7 +81,8 @@ int exec_dump_stack(VmState* st) { d = 255; } for (int i = d; i > 0; i--) { - std::cerr << stack[i - 1].to_string() << " "; + stack[i - 1].print_list(std::cerr); + std::cerr << ' '; } std::cerr << std::endl; return 0; @@ -83,9 +91,14 @@ int exec_dump_stack(VmState* st) { int exec_dump_value(VmState* st, unsigned arg) { arg &= 15; VM_LOG(st) << "execute DUMP s" << arg; + if (!vm_debug_enabled) { + return 0; + } Stack& stack = st->get_stack(); if ((int)arg < stack.depth()) { - std::cerr << "#DEBUG#: s" << arg << " = " << stack[arg].to_string() << std::endl; + std::cerr << "#DEBUG#: s" << arg << " = "; + stack[arg].print_list(std::cerr); + std::cerr << std::endl; } else { std::cerr << "#DEBUG#: s" << arg << " is absent" << std::endl; } diff --git a/submodules/ton/tonlib-src/crypto/vm/debugops.h b/submodules/ton/tonlib-src/crypto/vm/debugops.h index 7c7b27d010..ba3d673ff4 100644 --- a/submodules/ton/tonlib-src/crypto/vm/debugops.h +++ b/submodules/ton/tonlib-src/crypto/vm/debugops.h @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once @@ -25,5 +25,6 @@ class OpcodeTable; extern bool vm_debug_enabled; void register_debug_ops(OpcodeTable& cp0); +void set_debug_enabled(bool enable_debug); } // namespace vm diff --git a/submodules/ton/tonlib-src/crypto/vm/dict.cpp b/submodules/ton/tonlib-src/crypto/vm/dict.cpp index 7037e7e41c..fc94a2dc5a 100644 --- a/submodules/ton/tonlib-src/crypto/vm/dict.cpp +++ b/submodules/ton/tonlib-src/crypto/vm/dict.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "vm/dict.h" #include "vm/cells.h" @@ -179,7 +179,7 @@ bool DictionaryBase::append_dict_to_bool(CellBuilder& cb) && { return cb.store_maybe_ref(std::move(root_cell)); } -bool DictionaryBase::append_dict_to_bool(CellBuilder& cb) const& { +bool DictionaryBase::append_dict_to_bool(CellBuilder& cb) const & { return is_valid() && cb.store_maybe_ref(root_cell); } @@ -793,8 +793,7 @@ std::tuple, Ref, bool> dict_lookup_set(Ref dict, td:: std::pair, bool> pfx_dict_set(Ref dict, td::ConstBitPtr key, int m, int n, const PrefixDictionary::store_value_func_t& store_val, Dictionary::SetMode mode) { - std::cerr << "up to " << n << "-bit prefix code dictionary modification for " << m << "-bit key = " << key.to_hex(m) - << std::endl; + // std::cerr << "up to " << n << "-bit prefix code dictionary modification for " << m << "-bit key = " << key.to_hex(m) << std::endl; if (m > n) { return std::make_pair(Ref{}, false); } @@ -1309,6 +1308,294 @@ Ref Dictionary::extract_minmax_key_ref(td::BitPtr key_buffer, int key_len, return extract_value_ref(extract_minmax_key(key_buffer, key_len, fetch_max, invert_first)); } +/* + * + * ITERATORS (to be moved into a separate file) + * + */ + +bool DictIterator::prevalidate(int mode) { + if (key_bits_ <= 0 || key_bits_ > Dictionary::max_key_bits) { + reset(); + flags_ &= ~f_valid; + key_bits_ = 0; + return false; + } else { + if (mode >= 0) { + order_ = -(mode & 1) ^ ((mode >> 1) & 1); + } + flags_ |= f_valid; + return true; + } +} + +bool DictIterator::bind(const DictionaryFixed& dict, int do_rewind) { + if (!is_valid() || !is_bound_to(dict)) { + return false; + } + dict_ = &dict; + label_mode_ = dict.label_mode(); + return !do_rewind || rewind(do_rewind < 0); +} + +bool DictIterator::rebind_to(const DictionaryFixed& dict, int do_rewind) { + reset(); + dict_ = &dict; + label_mode_ = dict.label_mode(); + root_ = dict.get_root_cell(); + key_bits_ = dict.get_key_bits(); + flags_ &= 3; + return prevalidate() && (!do_rewind || rewind(do_rewind < 0)); +} + +int DictIterator::compare_keys(td::ConstBitPtr a, td::ConstBitPtr b) const { + if (!key_bits_) { + return 0; + } + int c = (int)*a - (int)*b; + if (c) { + return (order_ & 1) ? -c : c; + } + c = a.compare(b, key_bits_); + return order_ >= 0 ? c : -c; +} + +bool DictIterator::dive(int mode) { + int n = key_bits_, m = 0; + Ref node = path_.empty() ? root_ : path_.back().next; + if (!path_.empty()) { + m = path_.back().pos + 1; + n -= m; + mode >>= 1; + } + // similar to dict_lookup_minmax: create new path down until the leaf + while (1) { + LabelParser label{std::move(node), n, label_mode_}; + int l = label.extract_label_to(key(m)); + assert(l >= 0 && l <= n); + m += l; + n -= l; + if (!n) { + leaf_ = std::move(label.remainder); + return true; + } + if (l) { + mode >>= 1; + } + int bit = mode & 1; + node = label.remainder->prefetch_ref(bit); + auto alt = label.remainder->prefetch_ref(1 - bit); + path_.emplace_back(node, std::move(alt), m, bit); + *key(m++) = (bool)bit; + --n; + mode >>= 1; + } +} + +bool DictIterator::rewind(bool to_end) { + if (!is_valid()) { + return false; + } + if (root_.is_null()) { + return true; + } + auto node = root_; + int k = 0, mode = order_ ^ -(int)to_end; + // NB: can optimize by reusing several first entries of current path_ + while (k < (int)path_.size()) { + auto& pe = path_[k++]; + assert(pe.pos >= 0 && pe.pos < key_bits_); + if (pe.pos) { + mode >>= 1; + } + if (pe.v != (bool)(mode & 1)) { + // went different way at this node before, rotate and stop going down + pe.rotate(key()); + leaf_.clear(); + path_.resize(k); // drop the remainder of the original path after first incorrect branch + return dive(mode); + } + mode >>= 1; + } + return !eof() || dive(mode); +} + +bool DictIterator::next(bool go_back) { + if (!is_valid() || root_.is_null() || eof()) { + return false; + } + leaf_.clear(); + int mode = order_ ^ -(int)go_back; + while (!path_.empty()) { + auto& pe = path_.back(); + int bit = (mode >> (pe.pos > 0)) & 1; + if (pe.v == bit) { + pe.rotate(key()); + return dive(mode); + } + path_.pop_back(); + } + return false; +} + +bool DictIterator::lookup(td::ConstBitPtr pos, int pos_bits, bool strict_after, bool backw) { + if (!is_valid() || root_.is_null() || pos_bits < 0 || pos_bits > key_bits_) { + return false; + } + int fill_mode = -(strict_after ^ backw) ^ order_; + if (!eof()) { + // reuse part of current path + std::size_t bp0 = 0; + int bp; + if (!key().compare(pos, pos_bits, &bp0)) { + bp = pos_bits; + if (bp >= key_bits_) { + // already at the desired element + return !strict_after || next(backw); + } + } else { + bp = (int)bp0; + } + int k = 0; + while (k < (int)path_.size() && path_[k].pos <= bp) { + auto& pe = path_[k]; + if (pe.pos == bp) { + if (bp < pos_bits || pe.v != ((fill_mode >> (bp > 0)) & 1)) { + // rotate the last path element if it branched in incorrect direction + path_[k++].rotate(key()); + } + break; + } + ++k; + } + path_.resize(k); // drop the remainder of the path + } + int m = 0, n = key_bits_; + auto node = path_.empty() ? root_ : path_.back().next; + if (!path_.empty()) { + m = path_.back().pos + 1; // m <= pos_bits + 1 + n -= m; + } + int mode = -backw ^ order_, action = 0; + while (m < pos_bits && !action) { + LabelParser label{std::move(node), n, label_mode_}; + int pfx_len = label.common_prefix_len(pos + m, pos_bits - m); + int l = label.extract_label_to(key() + m); + assert(pfx_len >= 0 && pfx_len <= label.l_bits && label.l_bits <= n); + if (pfx_len == pos_bits - m) { + // end of given position prefix + if (strict_after) { + // have to backtrace + action = 2; + break; + } else { + // label has correct prefix, register and dive down + action = 1; + } + } else if (pfx_len < l) { + // all subtree is either smaller or larger than required + if (pos[m + pfx_len] != ((mode >> (int)(m + pfx_len > 0)) & 1)) { + // label smaller than required, have to backtrace + action = 2; + break; + } else { + // label larger than required, register node and dive down + action = 1; + } + } + // if we are here, then either action=1 (dive down activated) + // ... or l = pfx_len < pos_bits - m + // continue going down + m += l; + n -= l; + if (!n) { + // key found in a leaf + leaf_ = std::move(label.remainder); + return true; + } + bool bit = action ? ((mode >> (m > 0)) & 1) : pos[m]; + node = label.remainder->prefetch_ref(bit); + auto alt = label.remainder->prefetch_ref(1 - bit); + path_.emplace_back(node, std::move(alt), m, bit); + *key(m++) = (bool)bit; + --n; + } + if (!action) { + action = (strict_after ? 2 : 1); + } + if (action == 2) { + // have to backtrace to the "next" larger branch + // similar to next() + leaf_.clear(); + while (!path_.empty()) { + auto& pe = path_.back(); + int bit = (mode >> (pe.pos > 0)) & 1; + if (pe.v == bit) { + pe.rotate(key()); + return dive(mode); + } + path_.pop_back(); + } + return false; // eof: no suitable element + } + // action=1, dive down + return dive(mode); +} + +DictIterator DictionaryFixed::null_iterator() { + force_validate(); + return DictIterator{*this}; +} + +DictIterator DictionaryFixed::make_iterator(int mode) { + force_validate(); + DictIterator it{*this, mode}; + it.rewind(); + return it; +} + +DictIterator DictionaryFixed::init_iterator(bool backw, bool invert_first) { + return make_iterator((int)backw + 2 * (int)invert_first); +} + +DictIterator DictionaryFixed::begin() { + return init_iterator(); +} + +DictIterator DictionaryFixed::end() { + return null_iterator(); +} + +DictIterator DictionaryFixed::cbegin() { + return begin(); +} + +DictIterator DictionaryFixed::cend() { + return end(); +} + +DictIterator DictionaryFixed::rbegin() { + return init_iterator(true); +} + +DictIterator DictionaryFixed::rend() { + return null_iterator(); +} + +DictIterator DictionaryFixed::crbegin() { + return rbegin(); +} + +DictIterator DictionaryFixed::crend() { + return rend(); +} + +/* + * + * END (ITERATORS) + * + */ + std::pair, bool> DictionaryFixed::extract_prefix_subdict_internal(Ref dict, td::ConstBitPtr prefix, int prefix_len, bool remove_prefix) const { if (is_empty() || prefix_len <= 0) { @@ -2241,7 +2528,7 @@ Ref AugmentedDictionary::extract_root() && { return std::move(root); } -bool AugmentedDictionary::append_dict_to_bool(CellBuilder& cb) const& { +bool AugmentedDictionary::append_dict_to_bool(CellBuilder& cb) const & { if (!is_valid()) { return false; } @@ -2310,6 +2597,14 @@ Ref AugmentedDictionary::get_node_extra(Ref cell_ref, int n) co return {}; } +Ref AugmentedDictionary::extract_leaf_value(Ref leaf) const { + if (leaf.not_null() && aug.skip_extra(leaf.write())) { + return std::move(leaf); + } else { + return Ref{}; + } +} + Ref AugmentedDictionary::get_root_extra() const { return get_node_extra(root_cell, key_bits); } @@ -2536,7 +2831,7 @@ bool AugmentedDictionary::set(td::ConstBitPtr key, int key_len, const CellSlice& } auto res = dict_set(get_root_cell(), key, key_len, value, mode); if (res.second) { - //vm::CellSlice cs{vm::NoVm{}, res.first}; + //vm::CellSlice cs{vm::NoVmOrd(), res.first}; //std::cerr << "new augmented dictionary root is:\n"; //cs.print_rec(std::cerr); set_root_cell(std::move(res.first)); diff --git a/submodules/ton/tonlib-src/crypto/vm/dict.h b/submodules/ton/tonlib-src/crypto/vm/dict.h index 11234277dd..761c4073b7 100644 --- a/submodules/ton/tonlib-src/crypto/vm/dict.h +++ b/submodules/ton/tonlib-src/crypto/vm/dict.h @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once #include "common/bitstring.h" @@ -171,6 +171,13 @@ class DictionaryBase { } }; +class DictIterator; + +template +std::pair dict_range(T&& dict, bool rev = false, bool sgnd = false) { + return std::pair{std::forward(dict), (int)rev + 2 * (int)sgnd}; +} + class DictionaryFixed : public DictionaryBase { public: typedef std::function filter_func_t; @@ -199,6 +206,9 @@ class DictionaryFixed : public DictionaryBase { static BitSlice integer_key(td::RefInt256 x, unsigned n, bool sgnd = true, unsigned char buffer[128] = 0, bool quiet = false); static bool integer_key_simple(td::RefInt256 x, unsigned n, bool sgnd, td::BitPtr buffer, bool quiet = false); + td::RefInt256 key_as_integer(td::ConstBitPtr key, bool sgnd = false) const { + return td::bits_to_refint(key, key_bits, sgnd); + } bool key_exists(td::ConstBitPtr key, int key_len); bool int_key_exists(long long key); bool uint_key_exists(unsigned long long key); @@ -221,6 +231,17 @@ class DictionaryFixed : public DictionaryBase { bool scan_diff(DictionaryFixed& dict2, const scan_diff_func_t& diff_func, int check_augm = 0); bool validate_check(const foreach_func_t& foreach_func, bool invert_first = false); bool validate_all(); + DictIterator null_iterator(); + DictIterator init_iterator(bool backw = false, bool invert_first = false); + DictIterator make_iterator(int mode); + DictIterator begin(); + DictIterator end(); + DictIterator cbegin(); + DictIterator cend(); + DictIterator rbegin(); + DictIterator rend(); + DictIterator crbegin(); + DictIterator crend(); template bool key_exists(const T& key) { return key_exists(key.bits(), key.size()); @@ -237,11 +258,19 @@ class DictionaryFixed : public DictionaryBase { Ref get_minmax_key(T& key_buffer, bool fetch_max = false, bool invert_first = false) { return get_minmax_key(key_buffer.bits(), key_buffer.size(), fetch_max, invert_first); } + template + Ref lookup_nearest_key(T& key_buffer, bool fetch_next = false, bool allow_eq = false, + bool invert_first = false) { + return lookup_nearest_key(key_buffer.bits(), key_buffer.size(), fetch_next, allow_eq, invert_first); + } protected: virtual int label_mode() const { return dict::LabelParser::chk_all; } + virtual Ref extract_leaf_value(Ref leaf) const { + return leaf; + } virtual Ref finish_create_leaf(CellBuilder& cb, const CellSlice& value) const; virtual Ref finish_create_fork(CellBuilder& cb, Ref c1, Ref c2, int n) const; virtual bool check_fork(CellSlice& cs, Ref c1, Ref c2, int n) const { @@ -254,6 +283,7 @@ class DictionaryFixed : public DictionaryBase { return check_leaf(cs_ref.write(), key, key_len); } bool check_fork_raw(Ref cs_ref, int n) const; + friend class DictIterator; private: std::pair, Ref> dict_lookup_delete(Ref dict, td::ConstBitPtr key, int n) const; @@ -272,6 +302,148 @@ class DictionaryFixed : public DictionaryBase { const foreach_func_t& foreach_func, bool invert_first = false) const; }; +class DictIterator { + const DictionaryFixed* dict_{nullptr}; + Ref root_; + int label_mode_{dict::LabelParser::chk_size}; + int key_bits_; + int flags_; + int order_; + unsigned char key_buffer[DictionaryBase::max_key_bytes]; + bool prevalidate(int mode = -1); + enum { f_valid = 4 }; + + protected: + struct Fork { + Ref next, alt; + int pos; + bool v; + Fork() : pos(-1) { + } + Fork(Ref _next, Ref _alt, int _pos, bool _v) + : next(std::move(_next)), alt(std::move(_alt)), pos(_pos), v(_v) { + } + void rotate(td::BitPtr key) { + std::swap(next, alt); + key[pos] = (v ^= true); + } + }; + std::vector path_; + Ref leaf_; + + td::BitPtr key(int offs = 0) { + return td::BitPtr{key_buffer, offs}; + } + td::ConstBitPtr key(int offs = 0) const { + return td::ConstBitPtr{key_buffer, offs}; + } + td::ConstBitPtr ckey(int offs = 0) const { + return td::ConstBitPtr{key_buffer, offs}; + } + + public: + DictIterator() : key_bits_(0), flags_(0), order_(0) { + } + // mode: 0 = bidir, +4 = fwd only, +8 = back only; +1 = reverse directions, +2 = signed int keys + enum { it_reverse = 1, it_signed = 2 }; + DictIterator(Ref root_cell, int key_bits, int mode = 0) + : root_(std::move(root_cell)), key_bits_(key_bits), flags_(mode >> 2) { + prevalidate(mode & 3); + } + DictIterator(const DictionaryFixed& dict, int mode = 0) + : DictIterator(dict.get_root_cell(), dict.get_key_bits(), mode) { + dict_ = &dict; + label_mode_ = dict.label_mode(); + } + bool is_valid() const { + return flags_ & f_valid; + } + bool eof() const { + return leaf_.is_null(); + } + bool reset() { + dict_ = nullptr; + root_.clear(); + path_.clear(); + leaf_.clear(); + return true; + } + td::ConstBitPtr cur_pos() const { + return eof() ? td::ConstBitPtr{nullptr} : key(); + } + Ref get_root_cell() const { + return root_; + } + int get_key_bits() const { + return key_bits_; + } + bool is_bound() const { + return dict_; + } + bool is_bound_to(const DictionaryFixed& dict) const { + return root_.not_null() == dict.get_root_cell().not_null() && + (root_.not_null() ? root_.get() == dict.get_root_cell().get() : key_bits_ == dict.get_key_bits()); + } + bool bind(const DictionaryFixed& dict, int do_rewind = 0); + bool rebind_to(const DictionaryFixed& dict, int do_rewind = 0); + bool rewind(bool to_end = false); + bool next(bool backw = false); + bool prev() { + return next(true); + } + bool lookup(td::ConstBitPtr pos, int pos_bits, bool strict_after = false, bool backw = false); + template + bool lookup(const T& key, bool strict_after = false, bool backw = false) { + return lookup(key.bits(), key.size(), strict_after, backw); + } + Ref cur_value() const { + return dict_ ? dict_->extract_leaf_value(leaf_) : Ref{}; + } + Ref cur_value_raw() const { + return leaf_; + } + std::pair> operator*() const { + return std::make_pair(cur_pos(), cur_value()); + } + bool bound_to_same(const DictIterator& other) const { + return dict_ && dict_ == other.dict_; + } + bool operator==(const DictIterator& other) const { + return bound_to_same(other) && eof() == other.eof() && (eof() || key().equals(other.key(), key_bits_)); + } + int compare_keys(td::ConstBitPtr a, td::ConstBitPtr b) const; + bool operator<(const DictIterator& other) const { + return bound_to_same(other) && !eof() && (other.eof() || compare_keys(key(), other.key()) < 0); + } + bool operator!=(const DictIterator& other) const { + return !(operator==(other)); + } + bool operator>(const DictIterator& other) const { + return other < *this; + } + DictIterator& operator++() { + next(); + return *this; + } + DictIterator& operator--() { + next(true); + return *this; + } + + private: + bool dive(int mode); +}; + +template +DictIterator begin(std::pair dictm) { + return dictm.first.make_iterator(dictm.second); +} + +template +DictIterator end(std::pair dictm) { + return dictm.first.null_iterator(); +} + class Dictionary final : public DictionaryFixed { public: typedef std::function)> simple_map_func_t; @@ -351,6 +523,9 @@ class Dictionary final : public DictionaryFixed { Ref lookup_set_builder(const T& key, Ref val_ref, SetMode mode = SetMode::Set) { return lookup_set_builder(key.bits(), key.size(), std::move(val_ref), mode); } + auto range(bool rev = false, bool sgnd = false) { + return dict_range(*this, rev, sgnd); + } private: bool check_fork(CellSlice& cs, Ref c1, Ref c2, int n) const override { @@ -449,6 +624,9 @@ class AugmentedDictionary final : public DictionaryFixed { Ref lookup_delete_ref(const T& key) { return lookup_delete_ref(key.bits(), key.size()); } + auto range(bool rev = false, bool sgnd = false) { + return dict_range(*this, rev, sgnd); + } Ref extract_value(Ref value_extra) const; Ref extract_value_ref(Ref value_extra) const; @@ -458,6 +636,7 @@ class AugmentedDictionary final : public DictionaryFixed { private: bool compute_root() const; Ref get_node_extra(Ref cell_ref, int n) const; + Ref extract_leaf_value(Ref leaf) const override; bool check_leaf(CellSlice& cs, td::ConstBitPtr key, int key_len) const override; bool check_fork(CellSlice& cs, Ref c1, Ref c2, int n) const override; Ref finish_create_leaf(CellBuilder& cb, const CellSlice& value) const override; diff --git a/submodules/ton/tonlib-src/crypto/vm/dictops.cpp b/submodules/ton/tonlib-src/crypto/vm/dictops.cpp index 9f4faed9c6..c798b33397 100644 --- a/submodules/ton/tonlib-src/crypto/vm/dictops.cpp +++ b/submodules/ton/tonlib-src/crypto/vm/dictops.cpp @@ -14,14 +14,14 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include #include "vm/log.h" #include "vm/opctable.h" #include "vm/stack.hpp" -#include "vm/continuation.h" #include "vm/excno.hpp" +#include "vm/vm.h" #include "common/bigint.hpp" #include "common/refint.h" #include "vm/dictops.h" @@ -210,7 +210,7 @@ int exec_dict_get(VmState* st, unsigned args) { BitSlice key; unsigned char buffer[Dictionary::max_key_bytes]; if (args & 4) { - key = dict.integer_key(stack.pop_int(), n, !(args & 2), buffer, true); + key = dict.integer_key(stack.pop_int_finite(), n, !(args & 2), buffer, true); if (!key.is_valid()) { stack.push_smallint(0); return 0; @@ -250,7 +250,7 @@ int exec_dict_get_optref(VmState* st, unsigned args) { BitSlice key; unsigned char buffer[Dictionary::max_key_bytes]; if (args & 2) { - key = dict.integer_key(stack.pop_int(), n, !(args & 1), buffer, true); + key = dict.integer_key(stack.pop_int_finite(), n, !(args & 1), buffer, true); if (!key.is_valid()) { stack.push_null(); return 0; @@ -377,7 +377,7 @@ int exec_dict_delete(VmState* st, unsigned args) { BitSlice key; unsigned char buffer[Dictionary::max_key_bytes]; if (args & 2) { - key = dict.integer_key(stack.pop_int(), n, !(args & 1), buffer); + key = dict.integer_key(stack.pop_int_finite(), n, !(args & 1), buffer); if (!key.is_valid()) { push_dict(stack, std::move(dict)); stack.push_smallint(0); @@ -404,7 +404,7 @@ int exec_dict_deleteget(VmState* st, unsigned args) { BitSlice key; unsigned char buffer[Dictionary::max_key_bytes]; if (args & 4) { - key = dict.integer_key(stack.pop_int(), n, !(args & 2), buffer); + key = dict.integer_key(stack.pop_int_finite(), n, !(args & 2), buffer); if (!key.is_valid()) { push_dict(stack, std::move(dict)); stack.push_smallint(0); @@ -588,23 +588,29 @@ int exec_pfx_dict_delete(VmState* st) { int exec_dict_get_exec(VmState* st, unsigned args) { Stack& stack = st->get_stack(); - VM_LOG(st) << "execute DICT" << (args & 1 ? 'U' : 'I') << "GET" << (args & 2 ? "EXEC\n" : "JMP\n"); + VM_LOG(st) << "execute DICT" << (args & 1 ? 'U' : 'I') << "GET" << (args & 2 ? "EXEC" : "JMP") + << (args & 4 ? "Z" : ""); stack.check_underflow(3); int n = stack.pop_smallint_range(Dictionary::max_key_bits); Dictionary dict{stack.pop_maybe_cell(), n}; unsigned char buffer[Dictionary::max_key_bytes]; - dict.integer_key_simple(stack.pop_int(), n, !(args & 1), td::BitPtr{buffer}); - auto value = dict.lookup(td::BitPtr{buffer}, n); - if (value.not_null()) { - Ref cont{true, std::move(value), st->get_cp()}; - return (args & 2) ? st->call(std::move(cont)) : st->jump(std::move(cont)); - } else { - return 0; + auto idx = stack.pop_int_finite(); + if (dict.integer_key_simple(idx, n, !(args & 1), td::BitPtr{buffer}, true)) { + auto value = dict.lookup(td::BitPtr{buffer}, n); + if (value.not_null()) { + Ref cont{true, std::move(value), st->get_cp()}; + return (args & 2) ? st->call(std::move(cont)) : st->jump(std::move(cont)); + } } + // key not found or out of range + if (args & 4) { + stack.push_int(std::move(idx)); + } + return 0; } std::string dump_dict_get_exec(CellSlice& cs, unsigned args) { - return std::string{"DICT"} + (args & 1 ? 'U' : 'I') + "GET" + (args & 2 ? "EXEC" : "JMP"); + return std::string{"DICT"} + (args & 1 ? 'U' : 'I') + "GET" + (args & 2 ? "EXEC" : "JMP") + (args & 4 ? "Z" : ""); } int exec_push_const_dict(VmState* st, CellSlice& cs, unsigned args, int pfx_bits) { @@ -720,7 +726,7 @@ int exec_subdict_get(VmState* st, unsigned args) { BitSlice key; unsigned char buffer[Dictionary::max_key_bytes]; if (args & 2) { - key = dict.integer_key(stack.pop_int(), k, !(args & 1), buffer, true); + key = dict.integer_key(stack.pop_int_finite(), k, !(args & 1), buffer, true); } else { key = stack.pop_cellslice()->prefetch_bits(k); } @@ -805,7 +811,8 @@ void register_dictionary_ops(OpcodeTable& cp0) { exec_const_pfx_dict_switch, compute_len_push_const_dict)) .insert(OpcodeInstr::mkfixedrange(0xf4b1, 0xf4b4, 16, 3, std::bind(dump_subdictop2, _2, "GET"), exec_subdict_get)) .insert( - OpcodeInstr::mkfixedrange(0xf4b5, 0xf4b8, 16, 3, std::bind(dump_subdictop2, _2, "RPGET"), exec_subdict_get)); + OpcodeInstr::mkfixedrange(0xf4b5, 0xf4b8, 16, 3, std::bind(dump_subdictop2, _2, "RPGET"), exec_subdict_get)) + .insert(OpcodeInstr::mkfixed(0xf4bc >> 2, 14, 2, dump_dict_get_exec, exec_dict_get_exec)); } } // namespace vm diff --git a/submodules/ton/tonlib-src/crypto/vm/log.h b/submodules/ton/tonlib-src/crypto/vm/log.h index e063141135..30ace2c479 100644 --- a/submodules/ton/tonlib-src/crypto/vm/log.h +++ b/submodules/ton/tonlib-src/crypto/vm/log.h @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once @@ -33,6 +33,12 @@ struct VmLog { td::LogOptions log_options{td::log_options}; enum { DumpStack = 2 }; int log_mask{1}; + static VmLog Null() { + VmLog res; + res.log_options.level = 0; + res.log_mask = 0; + return res; + } }; template diff --git a/submodules/ton/tonlib-src/crypto/vm/memo.cpp b/submodules/ton/tonlib-src/crypto/vm/memo.cpp new file mode 100644 index 0000000000..576f28f193 --- /dev/null +++ b/submodules/ton/tonlib-src/crypto/vm/memo.cpp @@ -0,0 +1,33 @@ +/* + This file is part of TON Blockchain Library. + + TON Blockchain Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + TON Blockchain Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with TON Blockchain Library. If not, see . + + Copyright 2020 Telegram Systems LLP +*/ +#include "vm/memo.h" +#include "vm/excno.hpp" + +namespace vm { +using td::Ref; + +bool FakeVmStateLimits::register_op(int op_units) { + bool ok = (ops_remaining -= op_units) >= 0; + if (!ok && !quiet) { + throw VmError{Excno::out_of_gas, "too many operations"}; + } + return ok; +} + +} // namespace vm diff --git a/submodules/ton/tonlib-src/crypto/vm/memo.h b/submodules/ton/tonlib-src/crypto/vm/memo.h new file mode 100644 index 0000000000..3aee39a6b6 --- /dev/null +++ b/submodules/ton/tonlib-src/crypto/vm/memo.h @@ -0,0 +1,37 @@ +/* + This file is part of TON Blockchain Library. + + TON Blockchain Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + TON Blockchain Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with TON Blockchain Library. If not, see . + + Copyright 2020 Telegram Systems LLP +*/ +#pragma once +#include "common/refcnt.hpp" +#include "vm/cells.h" +#include "vm/vmstate.h" + +namespace vm { +using td::Ref; + +class FakeVmStateLimits : public VmStateInterface { + long long ops_remaining; + bool quiet; + + public: + FakeVmStateLimits(long long max_ops = 1LL << 62, bool _quiet = true) : ops_remaining(max_ops), quiet(_quiet) { + } + bool register_op(int op_units = 1) override; +}; + +} // namespace vm diff --git a/submodules/ton/tonlib-src/crypto/vm/opctable.cpp b/submodules/ton/tonlib-src/crypto/vm/opctable.cpp index fbdc2578c1..d4f0f3e977 100644 --- a/submodules/ton/tonlib-src/crypto/vm/opctable.cpp +++ b/submodules/ton/tonlib-src/crypto/vm/opctable.cpp @@ -14,14 +14,14 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include #include #include "vm/opctable.h" #include "vm/cellslice.h" #include "vm/excno.hpp" -#include "vm/continuation.h" +#include "vm/vm.h" #include #include #include diff --git a/submodules/ton/tonlib-src/crypto/vm/stack.cpp b/submodules/ton/tonlib-src/crypto/vm/stack.cpp index 0b63aec9cc..43099927d5 100644 --- a/submodules/ton/tonlib-src/crypto/vm/stack.cpp +++ b/submodules/ton/tonlib-src/crypto/vm/stack.cpp @@ -14,12 +14,13 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "vm/stack.hpp" #include "vm/continuation.h" #include "vm/box.hpp" #include "vm/atom.h" +#include "vm/vmstate.h" namespace td { template class td::Cnt; @@ -45,6 +46,18 @@ const char* get_exception_msg(Excno exc_no) { } } +bool StackEntry::is_list(const StackEntry* se) { + Ref tuple; + while (!se->empty()) { + tuple = se->as_tuple_range(2, 2); + if (tuple.is_null()) { + return false; + } + se = &tuple->at(1); + } + return true; +} + static const char HEX_digits[] = "0123456789ABCDEF"; std::string str_to_hex(std::string data, std::string prefix) { @@ -62,6 +75,12 @@ std::string StackEntry::to_string() const { return std::move(os).str(); } +std::string StackEntry::to_lisp_string() const { + std::ostringstream os; + print_list(os); + return std::move(os).str(); +} + void StackEntry::dump(std::ostream& os) const { switch (tp) { case t_null: @@ -130,6 +149,12 @@ void StackEntry::print_list(std::ostream& os) const { break; case t_tuple: { const auto& tuple = *static_cast>(ref); + if (is_list()) { + os << '('; + tuple[0].print_list(os); + print_list_tail(os, &tuple[1]); + break; + } auto n = tuple.size(); if (!n) { os << "[]"; @@ -137,7 +162,7 @@ void StackEntry::print_list(std::ostream& os) const { os << "["; tuple[0].print_list(os); os << "]"; - } else if (n != 2) { + } else { os << "["; unsigned c = 0; for (const auto& entry : tuple) { @@ -147,10 +172,6 @@ void StackEntry::print_list(std::ostream& os) const { entry.print_list(os); } os << ']'; - } else { - os << '('; - tuple[0].print_list(os); - tuple[1].print_list_tail(os); } break; } @@ -159,26 +180,40 @@ void StackEntry::print_list(std::ostream& os) const { } } -void StackEntry::print_list_tail(std::ostream& os) const { - switch (tp) { - case t_null: - os << ')'; - break; - case t_tuple: { - const auto& tuple = *static_cast>(ref); - if (tuple.size() == 2) { - os << ' '; - tuple[0].print_list(os); - tuple[1].print_list_tail(os); - break; - } - } - // fall through - default: +void StackEntry::print_list_tail(std::ostream& os, const StackEntry* se) { + Ref tuple; + while (!se->empty()) { + tuple = se->as_tuple_range(2, 2); + if (tuple.is_null()) { os << " . "; - print_list(os); - os << ')'; + se->print_list(os); + break; + } + os << ' '; + tuple->at(0).print_list(os); + se = &tuple->at(1); } + os << ')'; +} + +StackEntry StackEntry::make_list(std::vector&& elems) { + StackEntry tail; + std::size_t n = elems.size(); + while (n > 0) { + --n; + tail = StackEntry{vm::make_tuple_ref(std::move(elems[n]), tail)}; + } + return tail; +} + +StackEntry StackEntry::make_list(const std::vector& elems) { + StackEntry tail; + std::size_t n = elems.size(); + while (n > 0) { + --n; + tail = StackEntry{vm::make_tuple_ref(elems[n], tail)}; + } + return tail; } StackEntry::StackEntry(Ref stack_ref) : ref(std::move(stack_ref)), tp(t_stack) { @@ -521,7 +556,7 @@ void Stack::push_int_quiet(td::RefInt256 val, bool quiet) { if (!quiet) { throw VmError{Excno::int_ov}; } else if (val->is_valid()) { - push(td::RefInt256{true}); + push(td::make_refint()); return; } } @@ -557,7 +592,7 @@ void Stack::push_builder(Ref cb) { } void Stack::push_smallint(long long val) { - push(td::RefInt256{true, val}); + push(td::make_refint(val)); } void Stack::push_bool(bool val) { @@ -611,13 +646,21 @@ Ref Stack::split_top(unsigned top_cnt, unsigned drop_cnt) { return new_stk; } -void Stack::dump(std::ostream& os, bool cr) const { +void Stack::dump(std::ostream& os, int mode) const { os << " [ "; - for (const auto& x : stack) { - os << x.to_string() << ' '; + if (mode & 2) { + for (const auto& x : stack) { + x.print_list(os); + os << ' '; + } + } else { + for (const auto& x : stack) { + x.dump(os); + os << ' '; + } } os << "] "; - if (cr) { + if (mode & 1) { os << std::endl; } } @@ -629,4 +672,252 @@ void Stack::push_maybe_cellslice(Ref cs) { push_maybe(std::move(cs)); } +/* + * + * SERIALIZE/DESERIALIZE STACK VALUES + * + */ + +bool StackEntry::serialize(vm::CellBuilder& cb, int mode) const { + auto* vsi = VmStateInterface::get(); + if (vsi && !vsi->register_op()) { + return false; + } + switch (tp) { + case t_null: + return cb.store_long_bool(0, 8); // vm_stk_null#00 = VmStackValue; + case t_int: { + auto val = as_int(); + if (!val->is_valid()) { + // vm_stk_nan#02ff = VmStackValue; + return cb.store_long_bool(0x02ff, 16); + } else if (!(mode & 1) && val->signed_fits_bits(64)) { + // vm_stk_tinyint#01 value:int64 = VmStackValue; + return cb.store_long_bool(1, 8) && cb.store_int256_bool(std::move(val), 64); + } else { + // vm_stk_int#0201_ value:int257 = VmStackValue; + return cb.store_long_bool(0x0200 / 2, 15) && cb.store_int256_bool(std::move(val), 257); + } + } + case t_cell: + // vm_stk_cell#03 cell:^Cell = VmStackValue; + return cb.store_long_bool(3, 8) && cb.store_ref_bool(as_cell()); + case t_slice: { + // _ cell:^Cell st_bits:(## 10) end_bits:(## 10) { st_bits <= end_bits } + // st_ref:(#<= 4) end_ref:(#<= 4) { st_ref <= end_ref } = VmCellSlice; + const auto& cs = *static_cast>(ref); + return ((mode & 0x1000) || cb.store_long_bool(4, 8)) // vm_stk_slice#04 _:VmCellSlice = VmStackValue; + && cb.store_ref_bool(cs.get_base_cell()) // _ cell:^Cell + && cb.store_long_bool(cs.cur_pos(), 10) // st_bits:(## 10) + && cb.store_long_bool(cs.cur_pos() + cs.size(), 10) // end_bits:(## 10) + && cb.store_long_bool(cs.cur_ref(), 3) // st_ref:(#<= 4) + && cb.store_long_bool(cs.cur_ref() + cs.size_refs(), 3); // end_ref:(#<= 4) + } + case t_builder: + // vm_stk_builder#05 cell:^Cell = VmStackValue; + return cb.store_long_bool(5, 8) && cb.store_ref_bool(as_builder()->finalize_copy()); + case t_vmcont: + // vm_stk_cont#06 cont:VmCont = VmStackValue; + return !(mode & 2) && cb.store_long_bool(6, 8) && as_cont()->serialize(cb); + case t_tuple: { + const auto& tuple = *static_cast>(ref); + auto n = tuple.size(); + // vm_stk_tuple#07 len:(## 16) data:(VmTuple len) = VmStackValue; + Ref head, tail; + vm::CellBuilder cb2; + for (std::size_t i = 0; i < n; i++) { + std::swap(head, tail); + if (i > 1 && + !(cb2.store_ref_bool(std::move(tail)) && cb2.store_ref_bool(std::move(head)) && cb2.finalize_to(head))) { + return false; + } + if (!(tuple[i].serialize(cb2, mode) && cb2.finalize_to(tail))) { + return false; + } + } + return cb.store_long_bool(7, 8) && cb.store_long_bool(n, 16) && (head.is_null() || cb.store_ref_bool(head)) && + (tail.is_null() || cb.store_ref_bool(tail)); + } + default: + return false; + } +} + +bool StackEntry::deserialize(CellSlice& cs, int mode) { + auto* vsi = VmStateInterface::get(); + if (vsi && !vsi->register_op()) { + return false; + } + clear(); + int t = (mode & 0xf000) ? ((mode >> 12) & 15) : (int)cs.prefetch_ulong(8); + switch (t) { + case 0: + // vm_stk_null#00 = VmStackValue; + return cs.advance(8); + case 1: { + // vm_stk_tinyint#01 value:int64 = VmStackValue; + td::RefInt256 val; + return !(mode & 1) && cs.advance(8) && cs.fetch_int256_to(64, val) && set_int(std::move(val)); + } + case 2: { + t = (int)cs.prefetch_ulong(16) & 0x1ff; + if (t == 0xff) { + // vm_stk_nan#02ff = VmStackValue; + return cs.advance(16) && set_int(td::make_refint()); + } else { + // vm_stk_int#0201_ value:int257 = VmStackValue; + td::RefInt256 val; + return cs.fetch_ulong(15) == 0x0200 / 2 && cs.fetch_int256_to(257, val) && set_int(std::move(val)); + } + } + case 3: { + // vm_stk_cell#03 cell:^Cell = VmStackValue; + return cs.have_refs() && cs.advance(8) && set(t_cell, cs.fetch_ref()); + } + case 4: { + // _ cell:^Cell st_bits:(## 10) end_bits:(## 10) { st_bits <= end_bits } + // st_ref:(#<= 4) end_ref:(#<= 4) { st_ref <= end_ref } = VmCellSlice; + // vm_stk_slice#04 _:VmCellSlice = VmStackValue; + unsigned st_bits, end_bits, st_ref, end_ref; + Ref cell; + Ref csr; + return ((mode & 0xf000) || cs.advance(8)) // vm_stk_slice#04 + && cs.fetch_ref_to(cell) // cell:^Cell + && cs.fetch_uint_to(10, st_bits) // st_bits:(## 10) + && cs.fetch_uint_to(10, end_bits) // end_bits:(## 10) + && st_bits <= end_bits // { st_bits <= end_bits } + && cs.fetch_uint_to(3, st_ref) // st_ref:(#<= 4) + && cs.fetch_uint_to(3, end_ref) // end_ref:(#<= 4) + && st_ref <= end_ref && end_ref <= 4 // { st_ref <= end_ref } + && (csr = load_cell_slice_ref(std::move(cell))).not_null() // load cell slice + && csr->have(end_bits, end_ref) && + csr.write().skip_last(csr->size() - end_bits, csr->size_refs() - end_ref) && + csr.write().skip_first(st_bits, st_ref) && set(t_slice, std::move(csr)); + } + case 5: { + // vm_stk_builder#05 cell:^Cell = VmStackValue; + Ref cell; + Ref csr; + Ref cb{true}; + return cs.advance(8) && cs.fetch_ref_to(cell) && (csr = load_cell_slice_ref(std::move(cell))).not_null() && + cb.write().append_cellslice_bool(std::move(csr)) && set(t_builder, std::move(cb)); + } + case 6: { + // vm_stk_cont#06 cont:VmCont = VmStackValue; + Ref cont; + return !(mode & 2) && cs.advance(8) && Continuation::deserialize_to(cs, cont, mode) && + set(t_vmcont, std::move(cont)); + } + case 7: { + // vm_stk_tuple#07 len:(## 16) data:(VmTuple len) = VmStackValue; + int n; + if (!(cs.advance(8) && cs.fetch_uint_to(16, n))) { + return false; + } + Ref tuple{true, n}; + auto& t = tuple.write(); + if (n > 1) { + Ref head, tail; + n--; + if (!(cs.fetch_ref_to(head) && cs.fetch_ref_to(tail) && t[n].deserialize(std::move(tail), mode))) { + return false; + } + vm::CellSlice cs2; + while (--n > 0) { + if (!(cs2.load(std::move(head)) && cs2.fetch_ref_to(head) && cs2.fetch_ref_to(tail) && cs2.empty_ext() && + t[n].deserialize(std::move(tail), mode))) { + return false; + } + } + if (!t[0].deserialize(std::move(head), mode)) { + return false; + } + } else if (n == 1) { + return cs.have_refs() && t[0].deserialize(cs.fetch_ref(), mode) && set(t_tuple, std::move(tuple)); + } + return set(t_tuple, std::move(tuple)); + } + default: + return false; + } +} + +bool StackEntry::deserialize(Ref cell, int mode) { + if (cell.is_null()) { + clear(); + return false; + } + CellSlice cs = load_cell_slice(std::move(cell)); + return deserialize(cs, mode) && cs.empty_ext(); +} + +bool Stack::serialize(vm::CellBuilder& cb, int mode) const { + auto* vsi = VmStateInterface::get(); + if (vsi && !vsi->register_op()) { + return false; + } + // vm_stack#_ depth:(## 24) stack:(VmStackList depth) = VmStack; + unsigned n = depth(); + if (!cb.store_ulong_rchk_bool(n, 24)) { // vm_stack#_ depth:(## 24) + return false; + } + if (!n) { + return true; + } + vm::CellBuilder cb2; + Ref rest = cb2.finalize(); // vm_stk_nil#_ = VmStackList 0; + for (unsigned i = 0; i < n - 1; i++) { + // vm_stk_cons#_ {n:#} rest:^(VmStackList n) tos:VmStackValue = VmStackList (n + 1); + if (!(cb2.store_ref_bool(std::move(rest)) && stack[i].serialize(cb2, mode) && cb2.finalize_to(rest))) { + return false; + } + } + return cb.store_ref_bool(std::move(rest)) && stack[n - 1].serialize(cb, mode); +} + +bool Stack::deserialize(vm::CellSlice& cs, int mode) { + auto* vsi = VmStateInterface::get(); + if (vsi && !vsi->register_op()) { + return false; + } + clear(); + // vm_stack#_ depth:(## 24) stack:(VmStackList depth) = VmStack; + int n; + if (!cs.fetch_uint_to(24, n)) { + return false; + } + if (!n) { + return true; + } + stack.resize(n); + Ref rest; + if (!(cs.fetch_ref_to(rest) && stack[n - 1].deserialize(cs, mode))) { + clear(); + return false; + } + for (int i = n - 2; i >= 0; --i) { + // vm_stk_cons#_ {n:#} rest:^(VmStackList n) tos:VmStackValue = VmStackList (n + 1); + vm::CellSlice cs2 = load_cell_slice(std::move(rest)); + if (!(cs2.fetch_ref_to(rest) && stack[i].deserialize(cs2, mode) && cs2.empty_ext())) { + clear(); + return false; + } + } + if (!load_cell_slice(std::move(rest)).empty_ext()) { + clear(); + return false; + } + return true; +} + +bool Stack::deserialize_to(vm::CellSlice& cs, Ref& stack, int mode) { + stack = Ref{true}; + if (stack.unique_write().deserialize(cs, mode)) { + return true; + } else { + stack.clear(); + return false; + } +} + } // namespace vm diff --git a/submodules/ton/tonlib-src/crypto/vm/stack.hpp b/submodules/ton/tonlib-src/crypto/vm/stack.hpp index 0b16f59c39..3fadce6b27 100644 --- a/submodules/ton/tonlib-src/crypto/vm/stack.hpp +++ b/submodules/ton/tonlib-src/crypto/vm/stack.hpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once @@ -57,6 +57,11 @@ class Atom; using Tuple = td::Cnt>; +template +Ref make_tuple_ref(Args&&... args) { + return td::make_cnt_ref>(std::vector{std::forward(args)...}); +} + struct from_object_t {}; constexpr from_object_t from_object{}; @@ -130,6 +135,9 @@ class StackEntry { tp = t_null; return *this; } + bool set_int(td::RefInt256 value) { + return set(t_int, std::move(value)); + } bool empty() const { return tp == t_null; } @@ -139,9 +147,24 @@ class StackEntry { bool is_atom() const { return tp == t_atom; } + bool is_int() const { + return tp == t_int; + } + bool is_cell() const { + return tp == t_cell; + } + bool is_null() const { + return tp == t_null; + } bool is(int wanted) const { return tp == wanted; } + bool is_list() const { + return is_list(this); + } + static bool is_list(const StackEntry& se) { + return is_list(&se); + } void swap(StackEntry& se) { ref.swap(se.ref); std::swap(tp, se.tp); @@ -155,10 +178,15 @@ class StackEntry { Type type() const { return tp; } + // mode: +1 = disable short ints, +2 = disable continuations + bool serialize(vm::CellBuilder& cb, int mode = 0) const; + bool deserialize(vm::CellSlice& cs, int mode = 0); + bool deserialize(Ref cell, int mode = 0); private: + static bool is_list(const StackEntry* se); template - Ref dynamic_as() const& { + Ref dynamic_as() const & { return tp == tag ? static_cast>(ref) : td::Ref{}; } template @@ -170,7 +198,7 @@ class StackEntry { return tp == tag ? static_cast>(std::move(ref)) : td::Ref{}; } template - Ref as() const& { + Ref as() const & { return tp == tag ? Ref{td::static_cast_ref(), ref} : td::Ref{}; } template @@ -181,8 +209,19 @@ class StackEntry { Ref move_as() & { return tp == tag ? Ref{td::static_cast_ref(), std::move(ref)} : td::Ref{}; } + bool set(Type _tp, RefAny _ref) { + tp = _tp; + ref = std::move(_ref); + return ref.not_null() || tp == t_null; + } public: + static StackEntry make_list(std::vector&& elems); + static StackEntry make_list(const std::vector& elems); + template + static StackEntry cons(T1&& x, T2&& y) { + return StackEntry{make_tuple_ref(std::forward(x), std::forward(y))}; + } template static StackEntry maybe(Ref ref) { if (ref.is_null()) { @@ -191,31 +230,31 @@ class StackEntry { return ref; } } - td::RefInt256 as_int() const& { + td::RefInt256 as_int() const & { return as(); } td::RefInt256 as_int() && { return move_as(); } - Ref as_cell() const& { + Ref as_cell() const & { return as(); } Ref as_cell() && { return move_as(); } - Ref as_builder() const& { + Ref as_builder() const & { return as(); } Ref as_builder() && { return move_as(); } - Ref as_slice() const& { + Ref as_slice() const & { return as(); } Ref as_slice() && { return move_as(); } - Ref as_cont() const&; + Ref as_cont() const &; Ref as_cont() &&; Ref> as_string_ref() const { return as, t_string>(); @@ -230,16 +269,16 @@ class StackEntry { std::string as_bytes() const { return tp == t_bytes ? *as_bytes_ref() : ""; } - Ref as_box() const&; + Ref as_box() const &; Ref as_box() &&; - Ref as_tuple() const&; + Ref as_tuple() const &; Ref as_tuple() &&; - Ref as_tuple_range(unsigned max_len = 255, unsigned min_len = 0) const&; + Ref as_tuple_range(unsigned max_len = 255, unsigned min_len = 0) const &; Ref as_tuple_range(unsigned max_len = 255, unsigned min_len = 0) &&; - Ref as_atom() const&; + Ref as_atom() const &; Ref as_atom() &&; template - Ref as_object() const& { + Ref as_object() const & { return dynamic_as(); } template @@ -248,19 +287,17 @@ class StackEntry { } void dump(std::ostream& os) const; void print_list(std::ostream& os) const; - void print_list_tail(std::ostream& os) const; std::string to_string() const; + std::string to_lisp_string() const; + + private: + static void print_list_tail(std::ostream& os, const StackEntry* se); }; inline void swap(StackEntry& se1, StackEntry& se2) { se1.swap(se2); } -template -Ref make_tuple_ref(Args&&... args) { - return td::make_cnt_ref>(std::vector{std::forward(args)...}); -} - const StackEntry& tuple_index(const Tuple& tup, unsigned idx); StackEntry tuple_extend_index(const Ref& tup, unsigned idx); unsigned tuple_extend_set_index(Ref& tup, unsigned idx, StackEntry&& value, bool force = false); @@ -320,6 +357,10 @@ class Stack : public td::CntObject { void pop_many(int count) { stack.resize(stack.size() - count); } + void pop_many(int count, int offs) { + std::move(stack.cend() - offs, stack.cend(), stack.end() - (count + offs)); + pop_many(count); + } void drop_bottom(int count) { std::move(stack.cbegin() + count, stack.cend(), stack.begin()); pop_many(count); @@ -401,6 +442,12 @@ class Stack : public td::CntObject { } return *this; } + std::vector extract_contents() const & { + return stack; + } + std::vector extract_contents() && { + return std::move(stack); + } template const Stack& check_underflow(Args... args) const { if (!at_least(args...)) { @@ -453,6 +500,18 @@ class Stack : public td::CntObject { Ref pop_atom(); std::string pop_string(); std::string pop_bytes(); + template + Ref pop_object() { + return pop_chk().as_object(); + } + template + Ref pop_object_type_chk() { + auto res = pop_object(); + if (!res) { + throw VmError{Excno::type_chk, "not an object of required type"}; + } + return res; + } void push_null(); void push_int(td::RefInt256 val); void push_int_quiet(td::RefInt256 val, bool quiet = true); @@ -490,7 +549,11 @@ class Stack : public td::CntObject { push(std::move(val)); } } - void dump(std::ostream& os, bool cr = true) const; + // mode: +1 = add eoln, +2 = Lisp-style lists + void dump(std::ostream& os, int mode = 1) const; + bool serialize(vm::CellBuilder& cb, int mode = 0) const; + bool deserialize(vm::CellSlice& cs, int mode = 0); + static bool deserialize_to(vm::CellSlice& cs, Ref& stack, int mode = 0); }; } // namespace vm diff --git a/submodules/ton/tonlib-src/crypto/vm/stackops.cpp b/submodules/ton/tonlib-src/crypto/vm/stackops.cpp index 7fdbcba044..0f5be6d402 100644 --- a/submodules/ton/tonlib-src/crypto/vm/stackops.cpp +++ b/submodules/ton/tonlib-src/crypto/vm/stackops.cpp @@ -14,14 +14,14 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "vm/log.h" #include "vm/stackops.h" #include "vm/opctable.h" #include "vm/stack.hpp" -#include "vm/continuation.h" #include "vm/excno.hpp" +#include "vm/vm.h" namespace vm { @@ -379,6 +379,15 @@ int exec_blkdrop(VmState* st, unsigned args) { return 0; } +int exec_blkdrop2(VmState* st, unsigned args) { + int x = ((args >> 4) & 15), y = (args & 15); + Stack& stack = st->get_stack(); + VM_LOG(st) << "execute BLKDROP2 " << x << ',' << y; + stack.check_underflow(x + y); + stack.pop_many(x, y); + return 0; +} + int exec_blkpush(VmState* st, unsigned args) { int x = ((args >> 4) & 15), y = (args & 15); Stack& stack = st->get_stack(); @@ -570,7 +579,8 @@ void register_stack_ops(OpcodeTable& cp0) { .insert(OpcodeInstr::mksimple(0x68, 8, "DEPTH", exec_depth)) .insert(OpcodeInstr::mksimple(0x69, 8, "CHKDEPTH", exec_chkdepth)) .insert(OpcodeInstr::mksimple(0x6a, 8, "ONLYTOPX", exec_onlytop_x)) - .insert(OpcodeInstr::mksimple(0x6b, 8, "ONLYX", exec_only_x)); + .insert(OpcodeInstr::mksimple(0x6b, 8, "ONLYX", exec_only_x)) + .insert(OpcodeInstr::mkfixedrange(0x6c10, 0x6d00, 16, 8, instr::dump_2c("BLKDROP2 ", ","), exec_blkdrop2)); } } // namespace vm diff --git a/submodules/ton/tonlib-src/crypto/vm/tonops.cpp b/submodules/ton/tonlib-src/crypto/vm/tonops.cpp index e2142f072f..ca8e4b009f 100644 --- a/submodules/ton/tonlib-src/crypto/vm/tonops.cpp +++ b/submodules/ton/tonlib-src/crypto/vm/tonops.cpp @@ -14,15 +14,15 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include #include "vm/tonops.h" #include "vm/log.h" #include "vm/opctable.h" #include "vm/stack.hpp" -#include "vm/continuation.h" #include "vm/excno.hpp" +#include "vm/vm.h" #include "vm/dict.h" #include "Ed25519.h" @@ -77,7 +77,7 @@ int exec_set_gas_limit(VmState* st) { int exec_commit(VmState* st) { VM_LOG(st) << "execute COMMIT"; - st->commit(); + st->force_commit(); return 0; } @@ -165,6 +165,8 @@ int exec_set_global_common(VmState* st, unsigned idx) { if (idx >= 255) { throw VmError{Excno::range_chk, "tuple index out of range"}; } + static auto empty_tuple = Ref{true}; + st->set_c7(empty_tuple); // optimization; use only if no exception can be thrown until true set_c7() auto tpay = tuple_extend_set_index(tuple, idx, std::move(x)); if (tpay > 0) { st->consume_tuple_gas(tpay); @@ -193,7 +195,8 @@ void register_ton_config_ops(OpcodeTable& cp0) { .insert(OpcodeInstr::mksimple(0xf823, 16, "NOW", std::bind(exec_get_param, _1, 3, "NOW"))) .insert(OpcodeInstr::mksimple(0xf824, 16, "BLOCKLT", std::bind(exec_get_param, _1, 4, "BLOCKLT"))) .insert(OpcodeInstr::mksimple(0xf825, 16, "LTIME", std::bind(exec_get_param, _1, 5, "LTIME"))) - .insert(OpcodeInstr::mkfixedrange(0xf826, 0xf828, 16, 4, instr::dump_1c("GETPARAM "), exec_get_var_param)) + .insert(OpcodeInstr::mksimple(0xf826, 16, "RANDSEED", std::bind(exec_get_param, _1, 6, "RANDSEED"))) + .insert(OpcodeInstr::mksimple(0xf827, 16, "BALANCE", std::bind(exec_get_param, _1, 7, "BALANCE"))) .insert(OpcodeInstr::mksimple(0xf828, 16, "MYADDR", std::bind(exec_get_param, _1, 8, "MYADDR"))) .insert(OpcodeInstr::mksimple(0xf829, 16, "CONFIGROOT", std::bind(exec_get_param, _1, 9, "CONFIGROOT"))) .insert(OpcodeInstr::mkfixedrange(0xf82a, 0xf830, 16, 4, instr::dump_1c("GETPARAM "), exec_get_var_param)) @@ -206,6 +209,112 @@ void register_ton_config_ops(OpcodeTable& cp0) { .insert(OpcodeInstr::mkfixedrange(0xf861, 0xf880, 16, 5, instr::dump_1c_and(31, "SETGLOB "), exec_set_global)); } +static constexpr int randseed_idx = 6; + +td::RefInt256 generate_randu256(VmState* st) { + auto tuple = st->get_c7(); + auto t1 = tuple_index(*tuple, 0).as_tuple_range(255); + if (t1.is_null()) { + throw VmError{Excno::type_chk, "intermediate value is not a tuple"}; + } + auto seedv = tuple_index(*t1, randseed_idx).as_int(); + if (seedv.is_null()) { + throw VmError{Excno::type_chk, "random seed is not an integer"}; + } + unsigned char seed[32]; + if (!seedv->export_bytes(seed, 32, false)) { + throw VmError{Excno::range_chk, "random seed out of range"}; + } + unsigned char hash[64]; + digest::hash_str(hash, seed, 32); + if (!seedv.write().import_bytes(hash, 32, false)) { + throw VmError{Excno::range_chk, "cannot store new random seed"}; + } + td::RefInt256 res{true}; + if (!res.write().import_bytes(hash + 32, 32, false)) { + throw VmError{Excno::range_chk, "cannot store new random number"}; + } + static auto empty_tuple = Ref{true}; + st->set_c7(empty_tuple); // optimization; use only if no exception can be thrown until true set_c7() + tuple.write()[0].clear(); + t1.write().at(randseed_idx) = std::move(seedv); + st->consume_tuple_gas(t1); + tuple.write().at(0) = std::move(t1); + st->consume_tuple_gas(tuple); + st->set_c7(std::move(tuple)); + return res; +} + +int exec_randu256(VmState* st) { + VM_LOG(st) << "execute RANDU256"; + st->get_stack().push_int(generate_randu256(st)); + return 0; +} + +int exec_rand_int(VmState* st) { + VM_LOG(st) << "execute RAND"; + auto& stack = st->get_stack(); + stack.check_underflow(1); + auto x = stack.pop_int_finite(); + auto y = generate_randu256(st); + typename td::BigInt256::DoubleInt tmp{0}; + tmp.add_mul(*x, *y); + tmp.rshift(256, -1).normalize(); + stack.push_int(td::make_refint(tmp)); + return 0; +} + +int exec_set_rand(VmState* st, bool mix) { + VM_LOG(st) << "execute " << (mix ? "ADDRAND" : "SETRAND"); + auto& stack = st->get_stack(); + stack.check_underflow(1); + auto x = stack.pop_int_finite(); + if (!x->unsigned_fits_bits(256)) { + throw VmError{Excno::range_chk, "new random seed out of range"}; + } + auto tuple = st->get_c7(); + auto t1 = tuple_index(*tuple, 0).as_tuple_range(255); + if (t1.is_null()) { + throw VmError{Excno::type_chk, "intermediate value is not a tuple"}; + } + if (mix) { + auto seedv = tuple_index(*t1, randseed_idx).as_int(); + if (seedv.is_null()) { + throw VmError{Excno::type_chk, "random seed is not an integer"}; + } + unsigned char buffer[64], hash[32]; + if (!std::move(seedv)->export_bytes(buffer, 32, false)) { + throw VmError{Excno::range_chk, "random seed out of range"}; + } + if (!x->export_bytes(buffer + 32, 32, false)) { + throw VmError{Excno::range_chk, "mixed seed value out of range"}; + } + digest::hash_str(hash, buffer, 64); + if (!x.write().import_bytes(hash, 32, false)) { + throw VmError{Excno::range_chk, "new random seed value out of range"}; + } + } + static auto empty_tuple = Ref{true}; + st->set_c7(empty_tuple); // optimization; use only if no exception can be thrown until true set_c7() + tuple.write()[0].clear(); + auto tpay = tuple_extend_set_index(t1, randseed_idx, std::move(x)); + if (tpay > 0) { + st->consume_tuple_gas(tpay); + } + tuple.unique_write()[0] = std::move(t1); + st->consume_tuple_gas(tuple); + st->set_c7(std::move(tuple)); + return 0; +} + +void register_prng_ops(OpcodeTable& cp0) { + using namespace std::placeholders; + cp0.insert(OpcodeInstr::mksimple(0xf810, 16, "RANDU256", exec_randu256)) + .insert(OpcodeInstr::mksimple(0xf811, 16, "RAND", exec_rand_int)) + .insert(OpcodeInstr::mksimple(0xf814, 16, "SETRAND", std::bind(exec_set_rand, _1, false))) + .insert(OpcodeInstr::mksimple(0xf815, 16, "ADDRAND", std::bind(exec_set_rand, _1, true))); +} + int exec_compute_hash(VmState* st, int mode) { VM_LOG(st) << "execute HASH" << (mode & 1 ? 'S' : 'C') << 'U'; Stack& stack = st->get_stack(); @@ -288,6 +397,83 @@ void register_ton_crypto_ops(OpcodeTable& cp0) { .insert(OpcodeInstr::mksimple(0xf911, 16, "CHKSIGNS", std::bind(exec_ed25519_check_signature, _1, true))); } +struct VmStorageStat { + td::uint64 cells{0}, bits{0}, refs{0}, limit; + td::HashSet visited; + VmStorageStat(td::uint64 _limit) : limit(_limit) { + } + bool add_storage(Ref cell); + bool add_storage(const CellSlice& cs); + bool check_visited(const CellHash& cell_hash) { + return visited.insert(cell_hash).second; + } + bool check_visited(const Ref& cell) { + return check_visited(cell->get_hash()); + } +}; + +bool VmStorageStat::add_storage(Ref cell) { + if (cell.is_null() || !check_visited(cell)) { + return true; + } + if (cells >= limit) { + return false; + } + ++cells; + bool special; + auto cs = load_cell_slice_special(std::move(cell), special); + return cs.is_valid() && add_storage(std::move(cs)); +} + +bool VmStorageStat::add_storage(const CellSlice& cs) { + bits += cs.size(); + refs += cs.size_refs(); + for (unsigned i = 0; i < cs.size_refs(); i++) { + if (!add_storage(cs.prefetch_ref(i))) { + return false; + } + } + return true; +} + +int exec_compute_data_size(VmState* st, int mode) { + VM_LOG(st) << (mode & 2 ? 'S' : 'C') << "DATASIZE" << (mode & 1 ? "Q" : ""); + Stack& stack = st->get_stack(); + stack.check_underflow(2); + auto bound = stack.pop_int(); + Ref cell; + Ref cs; + if (mode & 2) { + cs = stack.pop_cellslice(); + } else { + cell = stack.pop_maybe_cell(); + } + if (!bound->is_valid() || bound->sgn() < 0) { + throw VmError{Excno::range_chk, "finite non-negative integer expected"}; + } + VmStorageStat stat{bound->unsigned_fits_bits(63) ? bound->to_long() : (1ULL << 63) - 1}; + bool ok = (mode & 2 ? stat.add_storage(cs.write()) : stat.add_storage(std::move(cell))); + if (ok) { + stack.push_smallint(stat.cells); + stack.push_smallint(stat.bits); + stack.push_smallint(stat.refs); + } else if (!(mode & 1)) { + throw VmError{Excno::cell_ov, "scanned too many cells"}; + } + if (mode & 1) { + stack.push_bool(ok); + } + return 0; +} + +void register_ton_misc_ops(OpcodeTable& cp0) { + using namespace std::placeholders; + cp0.insert(OpcodeInstr::mksimple(0xf940, 16, "CDATASIZEQ", std::bind(exec_compute_data_size, _1, 1))) + .insert(OpcodeInstr::mksimple(0xf941, 16, "CDATASIZE", std::bind(exec_compute_data_size, _1, 0))) + .insert(OpcodeInstr::mksimple(0xf942, 16, "SDATASIZEQ", std::bind(exec_compute_data_size, _1, 3))) + .insert(OpcodeInstr::mksimple(0xf943, 16, "SDATASIZE", std::bind(exec_compute_data_size, _1, 2))); +} + int exec_load_var_integer(VmState* st, int len_bits, bool sgnd, bool quiet) { if (len_bits == 4 && !sgnd) { VM_LOG(st) << "execute LDGRAMS" << (quiet ? "Q" : ""); @@ -421,15 +607,15 @@ bool parse_maybe_anycast(CellSlice& cs, StackEntry& res) { bool parse_message_addr(CellSlice& cs, std::vector& res) { res.clear(); switch ((unsigned)cs.fetch_ulong(2)) { - case 0: // addr_none$00 = MsgAddressExt; - res.emplace_back(td::RefInt256{true, 0}); // -> (0) + case 0: // addr_none$00 = MsgAddressExt; + res.emplace_back(td::zero_refint()); // -> (0) return true; case 1: { // addr_extern$01 unsigned len; Ref addr; if (cs.fetch_uint_to(9, len) // len:(## 9) && cs.fetch_subslice_to(len, addr)) { // external_address:(bits len) = MsgAddressExt; - res.emplace_back(td::RefInt256{true, 1}); + res.emplace_back(td::make_refint(1)); res.emplace_back(std::move(addr)); return true; } @@ -442,9 +628,9 @@ bool parse_message_addr(CellSlice& cs, std::vector& res) { if (parse_maybe_anycast(cs, v) // anycast:(Maybe Anycast) && cs.fetch_int_to(8, workchain) // workchain_id:int8 && cs.fetch_subslice_to(256, addr)) { // address:bits256 = MsgAddressInt; - res.emplace_back(td::RefInt256{true, 2}); + res.emplace_back(td::make_refint(2)); res.emplace_back(std::move(v)); - res.emplace_back(td::RefInt256{true, workchain}); + res.emplace_back(td::make_refint(workchain)); res.emplace_back(std::move(addr)); return true; } @@ -458,9 +644,9 @@ bool parse_message_addr(CellSlice& cs, std::vector& res) { && cs.fetch_uint_to(9, len) // addr_len:(## 9) && cs.fetch_int_to(32, workchain) // workchain_id:int32 && cs.fetch_subslice_to(len, addr)) { // address:(bits addr_len) = MsgAddressInt; - res.emplace_back(td::RefInt256{true, 3}); + res.emplace_back(td::make_refint(3)); res.emplace_back(std::move(v)); - res.emplace_back(td::RefInt256{true, workchain}); + res.emplace_back(td::make_refint(workchain)); res.emplace_back(std::move(addr)); return true; } @@ -625,26 +811,24 @@ bool store_grams(CellBuilder& cb, td::RefInt256 value) { } int exec_reserve_raw(VmState* st, int mode) { - VM_LOG(st) << "execute RESERVERAW" << (mode & 1 ? "X" : ""); + VM_LOG(st) << "execute RAWRESERVE" << (mode & 1 ? "X" : ""); Stack& stack = st->get_stack(); - stack.check_underflow(2); - int f = stack.pop_smallint_range(3); - td::RefInt256 x; - Ref csr; + stack.check_underflow(2 + (mode & 1)); + int f = stack.pop_smallint_range(15); + Ref y; if (mode & 1) { - csr = stack.pop_cellslice(); - } else { - x = stack.pop_int_finite(); - if (td::sgn(x) < 0) { - throw VmError{Excno::range_chk, "amount of nanograms must be non-negative"}; - } + y = stack.pop_maybe_cell(); + } + auto x = stack.pop_int_finite(); + if (td::sgn(x) < 0) { + throw VmError{Excno::range_chk, "amount of nanograms must be non-negative"}; } CellBuilder cb; if (!(cb.store_ref_bool(get_actions(st)) // out_list$_ {n:#} prev:^(OutList n) && cb.store_long_bool(0x36e6b809, 32) // action_reserve_currency#36e6b809 && cb.store_long_bool(f, 8) // mode:(## 8) - && (mode & 1 ? cb.append_cellslice_bool(std::move(csr)) - : (store_grams(cb, std::move(x)) && cb.store_bool_bool(false))))) { + && store_grams(cb, std::move(x)) // + && cb.store_maybe_ref(std::move(y)))) { throw VmError{Excno::cell_ov, "cannot serialize raw reserved currency amount into an output action cell"}; } return install_output_action(st, cb.finalize()); @@ -662,19 +846,58 @@ int exec_set_code(VmState* st) { return install_output_action(st, cb.finalize()); } +int exec_set_lib_code(VmState* st) { + VM_LOG(st) << "execute SETLIBCODE"; + Stack& stack = st->get_stack(); + stack.check_underflow(2); + int mode = stack.pop_smallint_range(2); + auto code = stack.pop_cell(); + CellBuilder cb; + if (!(cb.store_ref_bool(get_actions(st)) // out_list$_ {n:#} prev:^(OutList n) + && cb.store_long_bool(0x26fa1dd4, 32) // action_change_library#26fa1dd4 + && cb.store_long_bool(mode * 2 + 1, 8) // mode:(## 7) { mode <= 2 } + && cb.store_ref_bool(std::move(code)))) { // libref:LibRef = OutAction; + throw VmError{Excno::cell_ov, "cannot serialize new library code into an output action cell"}; + } + return install_output_action(st, cb.finalize()); +} + +int exec_change_lib(VmState* st) { + VM_LOG(st) << "execute CHANGELIB"; + Stack& stack = st->get_stack(); + stack.check_underflow(2); + int mode = stack.pop_smallint_range(2); + auto hash = stack.pop_int_finite(); + if (!hash->unsigned_fits_bits(256)) { + throw VmError{Excno::range_chk, "library hash must be non-negative"}; + } + CellBuilder cb; + if (!(cb.store_ref_bool(get_actions(st)) // out_list$_ {n:#} prev:^(OutList n) + && cb.store_long_bool(0x26fa1dd4, 32) // action_change_library#26fa1dd4 + && cb.store_long_bool(mode * 2, 8) // mode:(## 7) { mode <= 2 } + && cb.store_int256_bool(hash, 256, false))) { // libref:LibRef = OutAction; + throw VmError{Excno::cell_ov, "cannot serialize library hash into an output action cell"}; + } + return install_output_action(st, cb.finalize()); +} + void register_ton_message_ops(OpcodeTable& cp0) { using namespace std::placeholders; cp0.insert(OpcodeInstr::mksimple(0xfb00, 16, "SENDRAWMSG", exec_send_raw_message)) - .insert(OpcodeInstr::mksimple(0xfb02, 16, "RESERVERAW", std::bind(exec_reserve_raw, _1, 0))) - .insert(OpcodeInstr::mksimple(0xfb03, 16, "RESERVERAWX", std::bind(exec_reserve_raw, _1, 1))) - .insert(OpcodeInstr::mksimple(0xfb04, 16, "SETCODE", exec_set_code)); + .insert(OpcodeInstr::mksimple(0xfb02, 16, "RAWRESERVE", std::bind(exec_reserve_raw, _1, 0))) + .insert(OpcodeInstr::mksimple(0xfb03, 16, "RAWRESERVEX", std::bind(exec_reserve_raw, _1, 1))) + .insert(OpcodeInstr::mksimple(0xfb04, 16, "SETCODE", exec_set_code)) + .insert(OpcodeInstr::mksimple(0xfb06, 16, "SETLIBCODE", exec_set_lib_code)) + .insert(OpcodeInstr::mksimple(0xfb07, 16, "CHANGELIB", exec_change_lib)); } void register_ton_ops(OpcodeTable& cp0) { register_basic_gas_ops(cp0); register_ton_gas_ops(cp0); + register_prng_ops(cp0); register_ton_config_ops(cp0); register_ton_crypto_ops(cp0); + register_ton_misc_ops(cp0); register_ton_currency_address_ops(cp0); register_ton_message_ops(cp0); } diff --git a/submodules/ton/tonlib-src/crypto/vm/tupleops.cpp b/submodules/ton/tonlib-src/crypto/vm/tupleops.cpp index de4de83465..ef906f6acd 100644 --- a/submodules/ton/tonlib-src/crypto/vm/tupleops.cpp +++ b/submodules/ton/tonlib-src/crypto/vm/tupleops.cpp @@ -14,14 +14,14 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "vm/log.h" #include "vm/stackops.h" #include "vm/opctable.h" #include "vm/stack.hpp" -#include "vm/continuation.h" #include "vm/excno.hpp" +#include "vm/vm.h" namespace vm { @@ -53,6 +53,23 @@ int exec_null_swap_if(VmState* st, bool cond, int depth) { return 0; } +int exec_null_swap_if_many(VmState* st, bool cond, int depth, int count) { + Stack& stack = st->get_stack(); + VM_LOG(st) << "execute NULL" << (depth ? "ROTR" : "SWAP") << (cond ? "IF" : "IFNOT") << count; + stack.check_underflow(depth + 1); + auto x = stack.pop_int_finite(); + if (!x->sgn() != cond) { + for (int i = 0; i < count; i++) { + stack.push({}); + } + for (int i = 0; i < depth; i++) { + swap(stack[i], stack[i + count]); + } + } + stack.push_int(std::move(x)); + return 0; +} + int exec_mktuple_common(VmState* st, unsigned n) { Stack& stack = st->get_stack(); stack.check_underflow(n); @@ -374,6 +391,10 @@ void register_tuple_ops(OpcodeTable& cp0) { .insert(OpcodeInstr::mksimple(0x6fa1, 16, "NULLSWAPIFNOT", std::bind(exec_null_swap_if, _1, false, 0))) .insert(OpcodeInstr::mksimple(0x6fa2, 16, "NULLROTRIF", std::bind(exec_null_swap_if, _1, true, 1))) .insert(OpcodeInstr::mksimple(0x6fa3, 16, "NULLROTRIFNOT", std::bind(exec_null_swap_if, _1, false, 1))) + .insert(OpcodeInstr::mksimple(0x6fa4, 16, "NULLSWAPIF2", std::bind(exec_null_swap_if_many, _1, true, 0, 2))) + .insert(OpcodeInstr::mksimple(0x6fa5, 16, "NULLSWAPIFNOT2", std::bind(exec_null_swap_if_many, _1, false, 0, 2))) + .insert(OpcodeInstr::mksimple(0x6fa6, 16, "NULLROTRIF2", std::bind(exec_null_swap_if_many, _1, true, 1, 2))) + .insert(OpcodeInstr::mksimple(0x6fa7, 16, "NULLROTRIFNOT2", std::bind(exec_null_swap_if_many, _1, false, 1, 2))) .insert(OpcodeInstr::mkfixed(0x6fb, 12, 4, dump_tuple_index2, exec_tuple_index2)) .insert(OpcodeInstr::mkfixed(0x6fc >> 2, 10, 6, dump_tuple_index3, exec_tuple_index3)); } diff --git a/submodules/ton/tonlib-src/crypto/vm/utils.cpp b/submodules/ton/tonlib-src/crypto/vm/utils.cpp new file mode 100644 index 0000000000..783bf13276 --- /dev/null +++ b/submodules/ton/tonlib-src/crypto/vm/utils.cpp @@ -0,0 +1,152 @@ +/* + This file is part of TON Blockchain Library. + + TON Blockchain Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + TON Blockchain Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with TON Blockchain Library. If not, see . + + Copyright 2019-2020 Telegram Systems LLP +*/ +#include "utils.h" + +namespace vm { + +td::Result convert_stack_entry(td::Slice word); +td::Result> parse_stack_entries_in(td::Slice& str, bool prefix_only = false); +td::Result parse_stack_entry_in(td::Slice& str, bool prefix_only = false); + +namespace { + +td::Slice& skip_spaces(td::Slice& str, const char* delims) { + while (str.size() > 0 && strchr(delims, str[0])) { + str.remove_prefix(1); + } + return str; +} + +td::Slice get_word(td::Slice& str, const char* delims, const char* specials) { + skip_spaces(str, delims); + + size_t p = 0; + while (p < str.size() && !strchr(delims, str[p])) { + if (specials && strchr(specials, str[p])) { + if (!p) { + p++; + } + break; + } + p++; + } + + td::Slice ret = str.copy().truncate(p); + str.remove_prefix(p); + return ret; +} + +} // namespace + +td::Result parse_stack_entry_in(td::Slice& str, bool prefix_only) { + auto word = get_word(str, " \t", "[()]"); + if (word.empty()) { + return td::Status::Error("stack value expected instead of end-of-line"); + } + if (word.size() == 1 && (word[0] == '[' || word[0] == '(')) { + int expected = (word[0] == '(' ? ')' : ']'); + TRY_RESULT(values, parse_stack_entries_in(str, true)); + word = get_word(str, " \t", "[()]"); + if (word.size() != 1 || word[0] != expected) { + return td::Status::Error("closing bracket expected"); + } + vm::StackEntry value; + if (expected == ']') { + value = vm::StackEntry{std::move(values)}; + } else { + value = vm::StackEntry::make_list(std::move(values)); + } + if (prefix_only || (skip_spaces(str, " \t").size() == 0)) { + return value; + } else { + return td::Status::Error("extra data at the end"); + } + } else { + return convert_stack_entry(word); + } +} + +td::Result convert_stack_entry(td::Slice str) { + if (str.empty() || str.size() > 65535) { + return td::Status::Error("too long string"); + } + int l = (int)str.size(); + if (str[0] == '"') { + vm::CellBuilder cb; + if (l == 1 || str.back() != '"' || l >= 127 + 2 || !cb.store_bytes_bool(str.data() + 1, l - 2)) { + return td::Status::Error("incomplete (or too long) string"); + } + return vm::StackEntry{vm::load_cell_slice_ref(cb.finalize())}; + } + if (l >= 3 && (str[0] == 'x' || str[0] == 'b') && str[1] == '{' && str.back() == '}') { + unsigned char buff[128]; + int bits = + (str[0] == 'x') + ? (int)td::bitstring::parse_bitstring_hex_literal(buff, sizeof(buff), str.begin() + 2, str.end() - 1) + : (int)td::bitstring::parse_bitstring_binary_literal(buff, sizeof(buff), str.begin() + 2, str.end() - 1); + if (bits < 0) { + return td::Status::Error("failed to parse raw b{...}/x{...} number"); + } + return vm::StackEntry{ + Ref{true, vm::CellBuilder().store_bits(td::ConstBitPtr{buff}, bits).finalize()}}; + } + auto num = td::make_refint(); + auto& x = num.unique_write(); + if (l >= 3 && str[0] == '0' && str[1] == 'x') { + if (x.parse_hex(str.data() + 2, l - 2) != l - 2) { + return td::Status::Error("failed to parse 0x... hex number"); + } + } else if (l >= 4 && str[0] == '-' && str[1] == '0' && str[2] == 'x') { + if (x.parse_hex(str.data() + 3, l - 3) != l - 3) { + return td::Status::Error("failed to parse -0x... hex number"); + } + x.negate().normalize(); + } else if (!l || x.parse_dec(str.data(), l) != l) { + return td::Status::Error("failed to parse dec number"); + } + return vm::StackEntry{std::move(num)}; +} + +td::Result> parse_stack_entries_in(td::Slice& str, bool prefix_only) { + std::vector ret; + while (!skip_spaces(str, " \t").empty()) { + auto c = str.copy(); + auto word = get_word(c, " \t", "[()]"); + if (word == "]" || word == ")") { + if (prefix_only) { + return ret; + } else { + return td::Status::Error("not paired closing bracket"); + } + } + TRY_RESULT(value, parse_stack_entry_in(str, true)); + ret.push_back(std::move(value)); + } + return ret; +} + +td::Result> parse_stack_entries(td::Slice str, bool prefix_only) { + return parse_stack_entries_in(str, prefix_only); +} + +td::Result parse_stack_entry(td::Slice str, bool prefix_only) { + return parse_stack_entry_in(str, prefix_only); +} + +} // namespace vm diff --git a/submodules/ton/tonlib-src/crypto/vm/utils.h b/submodules/ton/tonlib-src/crypto/vm/utils.h new file mode 100644 index 0000000000..34d761b1d2 --- /dev/null +++ b/submodules/ton/tonlib-src/crypto/vm/utils.h @@ -0,0 +1,29 @@ +/* + This file is part of TON Blockchain Library. + + TON Blockchain Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + TON Blockchain Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with TON Blockchain Library. If not, see . + + Copyright 2019-2020 Telegram Systems LLP +*/ +#pragma once +#include "stack.hpp" + +#include + +namespace vm { + +td::Result> parse_stack_entries(td::Slice str, bool prefix_only = false); +td::Result parse_stack_entry(td::Slice str, bool prefix_only = false); + +} // namespace vm diff --git a/submodules/ton/tonlib-src/crypto/vm/vm.cpp b/submodules/ton/tonlib-src/crypto/vm/vm.cpp new file mode 100644 index 0000000000..395e01d37d --- /dev/null +++ b/submodules/ton/tonlib-src/crypto/vm/vm.cpp @@ -0,0 +1,618 @@ +/* + This file is part of TON Blockchain Library. + + TON Blockchain Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + TON Blockchain Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with TON Blockchain Library. If not, see . + + Copyright 2017-2020 Telegram Systems LLP +*/ +#include "vm/dispatch.h" +#include "vm/continuation.h" +#include "vm/dict.h" +#include "vm/log.h" +#include "vm/vm.h" + +namespace vm { + +VmState::VmState() : cp(-1), dispatch(&dummy_dispatch_table), quit0(true, 0), quit1(true, 1) { + ensure_throw(init_cp(0)); + init_cregs(); +} + +VmState::VmState(Ref _code) + : code(std::move(_code)), cp(-1), dispatch(&dummy_dispatch_table), quit0(true, 0), quit1(true, 1) { + ensure_throw(init_cp(0)); + init_cregs(); +} + +VmState::VmState(Ref _code, Ref _stack, int flags, Ref _data, VmLog log, + std::vector> _libraries, Ref init_c7) + : code(std::move(_code)) + , stack(std::move(_stack)) + , cp(-1) + , dispatch(&dummy_dispatch_table) + , quit0(true, 0) + , quit1(true, 1) + , log(log) + , libraries(std::move(_libraries)) { + ensure_throw(init_cp(0)); + set_c4(std::move(_data)); + if (init_c7.not_null()) { + set_c7(std::move(init_c7)); + } + init_cregs(flags & 1, flags & 2); +} + +VmState::VmState(Ref _code, Ref _stack, const GasLimits& gas, int flags, Ref _data, VmLog log, + std::vector> _libraries, Ref init_c7) + : code(std::move(_code)) + , stack(std::move(_stack)) + , cp(-1) + , dispatch(&dummy_dispatch_table) + , quit0(true, 0) + , quit1(true, 1) + , log(log) + , gas(gas) + , libraries(std::move(_libraries)) { + ensure_throw(init_cp(0)); + set_c4(std::move(_data)); + if (init_c7.not_null()) { + set_c7(std::move(init_c7)); + } + init_cregs(flags & 1, flags & 2); +} + +Ref VmState::convert_code_cell(Ref code_cell) { + if (code_cell.is_null()) { + return {}; + } + Ref csr{true, NoVmOrd(), code_cell}; + if (csr->is_valid()) { + return csr; + } + return load_cell_slice_ref(CellBuilder{}.store_ref(std::move(code_cell)).finalize()); +} + +bool VmState::init_cp(int new_cp) { + const DispatchTable* dt = DispatchTable::get_table(new_cp); + if (dt) { + cp = new_cp; + dispatch = dt; + return true; + } else { + return false; + } +} + +bool VmState::set_cp(int new_cp) { + return new_cp == cp || init_cp(new_cp); +} + +void VmState::force_cp(int new_cp) { + if (!set_cp(new_cp)) { + throw VmError{Excno::inv_opcode, "unsupported codepage"}; + } +} + +// simple call to a continuation cont +int VmState::call(Ref cont) { + const ControlData* cont_data = cont->get_cdata(); + if (cont_data) { + if (cont_data->save.c[0].not_null()) { + // call reduces to a jump + return jump(std::move(cont)); + } + if (cont_data->stack.not_null() || cont_data->nargs >= 0) { + // if cont has non-empty stack or expects fixed number of arguments, call is not simple + return call(std::move(cont), -1, -1); + } + // create return continuation, to be stored into new c0 + Ref ret = Ref{true, std::move(code), cp}; + ret.unique_write().get_cdata()->save.set_c0(std::move(cr.c[0])); + cr.set_c0( + std::move(ret)); // set c0 to its final value before switching to cont; notice that cont.save.c0 is not set + return jump_to(std::move(cont)); + } + // create return continuation, to be stored into new c0 + Ref ret = Ref{true, std::move(code), cp}; + ret.unique_write().get_cdata()->save.set_c0(std::move(cr.c[0])); + // general implementation of a simple call + cr.set_c0(std::move(ret)); // set c0 to its final value before switching to cont; notice that cont.save.c0 is not set + return jump_to(std::move(cont)); +} + +// call with parameters to continuation cont +int VmState::call(Ref cont, int pass_args, int ret_args) { + const ControlData* cont_data = cont->get_cdata(); + if (cont_data) { + if (cont_data->save.c[0].not_null()) { + // call reduces to a jump + return jump(std::move(cont), pass_args); + } + int depth = stack->depth(); + if (pass_args > depth || cont_data->nargs > depth) { + throw VmError{Excno::stk_und, "stack underflow while calling a continuation: not enough arguments on stack"}; + } + if (cont_data->nargs > pass_args && pass_args >= 0) { + throw VmError{Excno::stk_und, + "stack underflow while calling a closure continuation: not enough arguments passed"}; + } + auto old_c0 = std::move(cr.c[0]); + // optimization(?): decrease refcnts of unused continuations in c[i] as early as possible + preclear_cr(cont_data->save); + // no exceptions should be thrown after this point + int copy = cont_data->nargs, skip = 0; + if (pass_args >= 0) { + if (copy >= 0) { + skip = pass_args - copy; + } else { + copy = pass_args; + } + } + // copy=-1 : pass whole stack, else pass top `copy` elements, drop next `skip` elements. + Ref new_stk; + if (cont_data->stack.not_null() && !cont_data->stack->is_empty()) { + // `cont` already has a stack, create resulting stack from it + if (copy < 0) { + copy = stack->depth(); + } + if (cont->is_unique()) { + // optimization: avoid copying stack if we hold the only copy of `cont` + new_stk = std::move(cont.unique_write().get_cdata()->stack); + } else { + new_stk = cont_data->stack; + } + new_stk.write().move_from_stack(get_stack(), copy); + if (skip > 0) { + get_stack().pop_many(skip); + } + } else if (copy >= 0) { + new_stk = get_stack().split_top(copy, skip); + } else { + new_stk = std::move(stack); + stack.clear(); + } + // create return continuation using the remainder of current stack + Ref ret = Ref{true, std::move(code), cp, std::move(stack), ret_args}; + ret.unique_write().get_cdata()->save.set_c0(std::move(old_c0)); + Ref ord_cont = static_cast>(cont); + set_stack(std::move(new_stk)); + cr.set_c0(std::move(ret)); // ??? if codepage of code in ord_cont is unknown, will end up with incorrect c0 + return jump_to(std::move(cont)); + } else { + // have no continuation data, situation is somewhat simpler + int depth = stack->depth(); + if (pass_args > depth) { + throw VmError{Excno::stk_und, "stack underflow while calling a continuation: not enough arguments on stack"}; + } + // create new stack from the top `pass_args` elements of the current stack + Ref new_stk = (pass_args >= 0 ? get_stack().split_top(pass_args) : std::move(stack)); + // create return continuation using the remainder of the current stack + Ref ret = Ref{true, std::move(code), cp, std::move(stack), ret_args}; + ret.unique_write().get_cdata()->save.set_c0(std::move(cr.c[0])); + set_stack(std::move(new_stk)); + cr.set_c0(std::move(ret)); // ??? if codepage of code in ord_cont is unknown, will end up with incorrect c0 + return jump_to(std::move(cont)); + } +} + +// simple jump to continuation cont +int VmState::jump(Ref cont) { + const ControlData* cont_data = cont->get_cdata(); + if (cont_data && (cont_data->stack.not_null() || cont_data->nargs >= 0)) { + // if cont has non-empty stack or expects fixed number of arguments, jump is not simple + return jump(std::move(cont), -1); + } else { + return jump_to(std::move(cont)); + } +} + +// general jump to continuation cont +int VmState::jump(Ref cont, int pass_args) { + const ControlData* cont_data = cont->get_cdata(); + if (cont_data) { + // first do the checks + int depth = stack->depth(); + if (pass_args > depth || cont_data->nargs > depth) { + throw VmError{Excno::stk_und, "stack underflow while jumping to a continuation: not enough arguments on stack"}; + } + if (cont_data->nargs > pass_args && pass_args >= 0) { + throw VmError{Excno::stk_und, + "stack underflow while jumping to closure continuation: not enough arguments passed"}; + } + // optimization(?): decrease refcnts of unused continuations in c[i] as early as possible + preclear_cr(cont_data->save); + // no exceptions should be thrown after this point + int copy = cont_data->nargs; + if (pass_args >= 0 && copy < 0) { + copy = pass_args; + } + // copy=-1 : pass whole stack, else pass top `copy` elements, drop the remainder. + if (cont_data->stack.not_null() && !cont_data->stack->is_empty()) { + // `cont` already has a stack, create resulting stack from it + if (copy < 0) { + copy = get_stack().depth(); + } + Ref new_stk; + if (cont->is_unique()) { + // optimization: avoid copying the stack if we hold the only copy of `cont` + new_stk = std::move(cont.unique_write().get_cdata()->stack); + } else { + new_stk = cont_data->stack; + } + new_stk.write().move_from_stack(get_stack(), copy); + set_stack(std::move(new_stk)); + } else { + if (copy >= 0) { + get_stack().drop_bottom(stack->depth() - copy); + } + } + return jump_to(std::move(cont)); + } else { + // have no continuation data, situation is somewhat simpler + if (pass_args >= 0) { + int depth = get_stack().depth(); + if (pass_args > depth) { + throw VmError{Excno::stk_und, "stack underflow while jumping to a continuation: not enough arguments on stack"}; + } + get_stack().drop_bottom(depth - pass_args); + } + return jump_to(std::move(cont)); + } +} + +int VmState::ret() { + Ref cont = quit0; + cont.swap(cr.c[0]); + return jump(std::move(cont)); +} + +int VmState::ret(int ret_args) { + Ref cont = quit0; + cont.swap(cr.c[0]); + return jump(std::move(cont), ret_args); +} + +int VmState::ret_alt() { + Ref cont = quit1; + cont.swap(cr.c[1]); + return jump(std::move(cont)); +} + +int VmState::ret_alt(int ret_args) { + Ref cont = quit1; + cont.swap(cr.c[1]); + return jump(std::move(cont), ret_args); +} + +Ref VmState::extract_cc(int save_cr, int stack_copy, int cc_args) { + Ref new_stk; + if (stack_copy < 0 || stack_copy == stack->depth()) { + new_stk = std::move(stack); + stack.clear(); + } else if (stack_copy > 0) { + stack->check_underflow(stack_copy); + new_stk = get_stack().split_top(stack_copy); + } else { + new_stk = Ref{true}; + } + Ref cc = Ref{true, std::move(code), cp, std::move(stack), cc_args}; + stack = std::move(new_stk); + if (save_cr & 7) { + ControlData* cdata = cc.unique_write().get_cdata(); + if (save_cr & 1) { + cdata->save.set_c0(std::move(cr.c[0])); + cr.set_c0(quit0); + } + if (save_cr & 2) { + cdata->save.set_c1(std::move(cr.c[1])); + cr.set_c1(quit1); + } + if (save_cr & 4) { + cdata->save.set_c2(std::move(cr.c[2])); + // cr.set_c2(Ref{true}); + } + } + return cc; +} + +int VmState::throw_exception(int excno) { + Stack& stack_ref = get_stack(); + stack_ref.clear(); + stack_ref.push_smallint(0); + stack_ref.push_smallint(excno); + code.clear(); + consume_gas(exception_gas_price); + return jump(get_c2()); +} + +int VmState::throw_exception(int excno, StackEntry&& arg) { + Stack& stack_ref = get_stack(); + stack_ref.clear(); + stack_ref.push(std::move(arg)); + stack_ref.push_smallint(excno); + code.clear(); + consume_gas(exception_gas_price); + return jump(get_c2()); +} + +void GasLimits::gas_exception() const { + throw VmNoGas{}; +} + +void GasLimits::set_limits(long long _max, long long _limit, long long _credit) { + gas_max = _max; + gas_limit = _limit; + gas_credit = _credit; + change_base(_limit + _credit); +} + +void GasLimits::change_limit(long long _limit) { + _limit = std::min(std::max(_limit, 0LL), gas_max); + gas_credit = 0; + gas_limit = _limit; + change_base(_limit); +} + +bool VmState::set_gas_limits(long long _max, long long _limit, long long _credit) { + gas.set_limits(_max, _limit, _credit); + return true; +} + +void VmState::change_gas_limit(long long new_limit) { + VM_LOG(this) << "changing gas limit to " << std::min(new_limit, gas.gas_max); + gas.change_limit(new_limit); +} + +int VmState::step() { + assert(!code.is_null()); + //VM_LOG(st) << "stack:"; stack->dump(VM_LOG(st)); + //VM_LOG(st) << "; cr0.refcnt = " << get_c0()->get_refcnt() - 1 << std::endl; + if (stack_trace) { + stack->dump(std::cerr, 3); + } + ++steps; + if (code->size()) { + return dispatch->dispatch(this, code.write()); + } else if (code->size_refs()) { + VM_LOG(this) << "execute implicit JMPREF"; + gas.consume_chk(implicit_jmpref_gas_price); + Ref cont = Ref{true, load_cell_slice_ref(code->prefetch_ref()), get_cp()}; + return jump(std::move(cont)); + } else { + VM_LOG(this) << "execute implicit RET"; + gas.consume_chk(implicit_ret_gas_price); + return ret(); + } +} + +int VmState::run() { + if (code.is_null()) { + throw VmError{Excno::fatal, "cannot run an uninitialized VM"}; + } + int res; + Guard guard(this); + do { + // LOG(INFO) << "[BS] data cells: " << DataCell::get_total_data_cells(); + try { + try { + try { + res = step(); + gas.check(); + } catch (vm::CellBuilder::CellWriteError) { + throw VmError{Excno::cell_ov}; + } catch (vm::CellBuilder::CellCreateError) { + throw VmError{Excno::cell_ov}; + } catch (vm::CellSlice::CellReadError) { + throw VmError{Excno::cell_und}; + } + } catch (const VmError& vme) { + VM_LOG(this) << "handling exception code " << vme.get_errno() << ": " << vme.get_msg(); + try { + // LOG(INFO) << "[EX] data cells: " << DataCell::get_total_data_cells(); + ++steps; + res = throw_exception(vme.get_errno()); + } catch (const VmError& vme2) { + VM_LOG(this) << "exception " << vme2.get_errno() << " while handling exception: " << vme.get_msg(); + // LOG(INFO) << "[EXX] data cells: " << DataCell::get_total_data_cells(); + return ~vme2.get_errno(); + } + } + } catch (VmNoGas vmoog) { + ++steps; + VM_LOG(this) << "unhandled out-of-gas exception: gas consumed=" << gas.gas_consumed() + << ", limit=" << gas.gas_limit; + get_stack().clear(); + get_stack().push_smallint(gas.gas_consumed()); + return vmoog.get_errno(); // no ~ for unhandled exceptions (to make their faking impossible) + } + } while (!res); + // LOG(INFO) << "[EN] data cells: " << DataCell::get_total_data_cells(); + if ((res | 1) == -1 && !try_commit()) { + VM_LOG(this) << "automatic commit failed (new data or action cells too deep)"; + get_stack().clear(); + get_stack().push_smallint(0); + return ~(int)Excno::cell_ov; + } + return res; +} + +bool VmState::try_commit() { + if (cr.d[0].not_null() && cr.d[1].not_null() && cr.d[0]->get_depth() <= max_data_depth && + cr.d[1]->get_depth() <= max_data_depth) { + cstate.c4 = cr.d[0]; + cstate.c5 = cr.d[1]; + cstate.committed = true; + return true; + } else { + return false; + } +} + +void VmState::force_commit() { + if (!try_commit()) { + throw VmError{Excno::cell_ov, "cannot commit too deep cells as new data/actions"}; + } +} + +ControlData* force_cdata(Ref& cont) { + if (!cont->get_cdata()) { + cont = Ref{true, cont}; + return cont.unique_write().get_cdata(); + } else { + return cont.write().get_cdata(); + } +} + +ControlRegs* force_cregs(Ref& cont) { + return &force_cdata(cont)->save; +} + +int run_vm_code(Ref code, Ref& stack, int flags, Ref* data_ptr, VmLog log, long long* steps, + GasLimits* gas_limits, std::vector> libraries, Ref init_c7, Ref* actions_ptr) { + VmState vm{code, + std::move(stack), + gas_limits ? *gas_limits : GasLimits{}, + flags, + data_ptr ? *data_ptr : Ref{}, + log, + std::move(libraries), + std::move(init_c7)}; + int res = vm.run(); + stack = vm.get_stack_ref(); + if (vm.committed() && data_ptr) { + *data_ptr = vm.get_committed_state().c4; + } + if (vm.committed() && actions_ptr) { + *actions_ptr = vm.get_committed_state().c5; + } + if (steps) { + *steps = vm.get_steps_count(); + } + if (gas_limits) { + *gas_limits = vm.get_gas_limits(); + LOG(INFO) << "steps: " << vm.get_steps_count() << " gas: used=" << gas_limits->gas_consumed() + << ", max=" << gas_limits->gas_max << ", limit=" << gas_limits->gas_limit + << ", credit=" << gas_limits->gas_credit; + } + if ((vm.get_log().log_mask & vm::VmLog::DumpStack) != 0) { + VM_LOG(&vm) << "BEGIN_STACK_DUMP"; + for (int i = stack->depth(); i > 0; i--) { + VM_LOG(&vm) << (*stack)[i - 1].to_string(); + } + VM_LOG(&vm) << "END_STACK_DUMP"; + } + + return ~res; +} + +int run_vm_code(Ref code, Stack& stack, int flags, Ref* data_ptr, VmLog log, long long* steps, + GasLimits* gas_limits, std::vector> libraries, Ref init_c7, Ref* actions_ptr) { + Ref stk{true}; + stk.unique_write().set_contents(std::move(stack)); + stack.clear(); + int res = run_vm_code(code, stk, flags, data_ptr, log, steps, gas_limits, std::move(libraries), std::move(init_c7), + actions_ptr); + CHECK(stack.is_unique()); + if (stk.is_null()) { + stack.clear(); + } else if (&(*stk) != &stack) { + VmState* st = nullptr; + if (stk->is_unique()) { + VM_LOG(st) << "move resulting stack (" << stk->depth() << " entries)"; + stack.set_contents(std::move(stk.unique_write())); + } else { + VM_LOG(st) << "copying resulting stack (" << stk->depth() << " entries)"; + stack.set_contents(*stk); + } + } + return res; +} + +// may throw a dictionary exception; returns nullptr if library is not found in context +Ref VmState::load_library(td::ConstBitPtr hash) { + std::unique_ptr tmp_ctx; + // install temporary dummy vm state interface to prevent charging for cell load operations during library lookup + VmStateInterface::Guard(tmp_ctx.get()); + for (const auto& lib_collection : libraries) { + auto lib = lookup_library_in(hash, lib_collection); + if (lib.not_null()) { + return lib; + } + } + return {}; +} + +bool VmState::register_library_collection(Ref lib) { + if (lib.is_null()) { + return true; + } + libraries.push_back(std::move(lib)); + return true; +} + +void VmState::register_cell_load(const CellHash& cell_hash) { + if (cell_load_gas_price == cell_reload_gas_price) { + consume_gas(cell_load_gas_price); + } else { + auto ok = loaded_cells.insert(cell_hash); // check whether this is the first time this cell is loaded + if (ok.second) { + loaded_cells_count++; + } + consume_gas(ok.second ? cell_load_gas_price : cell_reload_gas_price); + } +} + +void VmState::register_cell_create() { + consume_gas(cell_create_gas_price); +} + +td::BitArray<256> VmState::get_state_hash() const { + // TODO: implement properly, by serializing the stack etc, and computing the Merkle hash + td::BitArray<256> res; + res.clear(); + return res; +} + +td::BitArray<256> VmState::get_final_state_hash(int exit_code) const { + // TODO: implement properly, by serializing the stack etc, and computing the Merkle hash + td::BitArray<256> res; + res.clear(); + return res; +} + +Ref lookup_library_in(td::ConstBitPtr key, vm::Dictionary& dict) { + try { + auto val = dict.lookup(key, 256); + if (val.is_null() || !val->have_refs()) { + return {}; + } + auto root = val->prefetch_ref(); + if (root.not_null() && !root->get_hash().bits().compare(key, 256)) { + return root; + } + return {}; + } catch (vm::VmError) { + return {}; + } +} + +Ref lookup_library_in(td::ConstBitPtr key, Ref lib_root) { + if (lib_root.is_null()) { + return lib_root; + } + vm::Dictionary dict{std::move(lib_root), 256}; + return lookup_library_in(key, dict); +} + +} // namespace vm diff --git a/submodules/ton/tonlib-src/crypto/vm/vm.h b/submodules/ton/tonlib-src/crypto/vm/vm.h new file mode 100644 index 0000000000..19c3829f11 --- /dev/null +++ b/submodules/ton/tonlib-src/crypto/vm/vm.h @@ -0,0 +1,320 @@ +/* + This file is part of TON Blockchain Library. + + TON Blockchain Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + TON Blockchain Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with TON Blockchain Library. If not, see . + + Copyright 2017-2020 Telegram Systems LLP +*/ +#pragma once + +#include "common/refcnt.hpp" +#include "vm/cellslice.h" +#include "vm/stack.hpp" +#include "vm/vmstate.h" +#include "vm/log.h" +#include "vm/continuation.h" +#include "td/utils/HashSet.h" + +namespace vm { + +using td::Ref; +struct GasLimits { + static constexpr long long infty = (1ULL << 63) - 1; + long long gas_max, gas_limit, gas_credit, gas_remaining, gas_base; + GasLimits() : gas_max(infty), gas_limit(infty), gas_credit(0), gas_remaining(infty), gas_base(infty) { + } + GasLimits(long long _limit, long long _max = infty, long long _credit = 0) + : gas_max(_max) + , gas_limit(_limit) + , gas_credit(_credit) + , gas_remaining(_limit + _credit) + , gas_base(gas_remaining) { + } + long long gas_consumed() const { + return gas_base - gas_remaining; + } + void set_limits(long long _max, long long _limit, long long _credit = 0); + void change_base(long long _base) { + gas_remaining += _base - gas_base; + gas_base = _base; + } + void change_limit(long long _limit); + void consume(long long amount) { + // LOG(DEBUG) << "consume " << amount << " gas (" << gas_remaining << " remaining)"; + gas_remaining -= amount; + } + bool try_consume(long long amount) { + // LOG(DEBUG) << "try consume " << amount << " gas (" << gas_remaining << " remaining)"; + return (gas_remaining -= amount) >= 0; + } + void gas_exception() const; + void gas_exception(bool cond) const { + if (!cond) { + gas_exception(); + } + } + void consume_chk(long long amount) { + gas_exception(try_consume(amount)); + } + void check() const { + gas_exception(gas_remaining >= 0); + } + bool final_ok() const { + return gas_remaining >= gas_credit; + } +}; + +struct CommittedState { + Ref c4, c5; + bool committed{false}; +}; + +class VmState final : public VmStateInterface { + Ref code; + Ref stack; + ControlRegs cr; + CommittedState cstate; + int cp; + long long steps{0}; + const DispatchTable* dispatch; + Ref quit0, quit1; + VmLog log; + GasLimits gas; + std::vector> libraries; + td::HashSet loaded_cells; + td::int64 loaded_cells_count{0}; + int stack_trace{0}, debug_off{0}; + bool chksig_always_succeed{false}; + + public: + enum { + cell_load_gas_price = 100, + cell_reload_gas_price = 25, + cell_create_gas_price = 500, + exception_gas_price = 50, + tuple_entry_gas_price = 1, + implicit_jmpref_gas_price = 10, + implicit_ret_gas_price = 5, + max_data_depth = 512 + }; + VmState(); + VmState(Ref _code); + VmState(Ref _code, Ref _stack, int flags = 0, Ref _data = {}, VmLog log = {}, + std::vector> _libraries = {}, Ref init_c7 = {}); + VmState(Ref _code, Ref _stack, const GasLimits& _gas, int flags = 0, Ref _data = {}, + VmLog log = {}, std::vector> _libraries = {}, Ref init_c7 = {}); + template + VmState(Ref code_cell, Args&&... args) + : VmState(convert_code_cell(std::move(code_cell)), std::forward(args)...) { + } + VmState(const VmState&) = delete; + VmState(VmState&&) = delete; + VmState& operator=(const VmState&) = delete; + VmState& operator=(VmState&&) = delete; + bool set_gas_limits(long long _max, long long _limit, long long _credit = 0); + bool final_gas_ok() const { + return gas.final_ok(); + } + long long gas_consumed() const { + return gas.gas_consumed(); + } + bool committed() const { + return cstate.committed; + } + const CommittedState& get_committed_state() const { + return cstate; + } + void consume_gas(long long amount) { + gas.consume(amount); + } + void consume_tuple_gas(unsigned tuple_len) { + consume_gas(tuple_len * tuple_entry_gas_price); + } + void consume_tuple_gas(const Ref& tup) { + if (tup.not_null()) { + consume_tuple_gas((unsigned)tup->size()); + } + } + GasLimits get_gas_limits() const { + return gas; + } + void change_gas_limit(long long new_limit); + template + void check_underflow(Args... args) { + stack->check_underflow(args...); + } + bool register_library_collection(Ref lib); + Ref load_library( + td::ConstBitPtr hash) override; // may throw a dictionary exception; returns nullptr if library is not found + void register_cell_load(const CellHash& cell_hash) override; + void register_cell_create() override; + bool init_cp(int new_cp); + bool set_cp(int new_cp); + void force_cp(int new_cp); + int get_cp() const { + return cp; + } + int incr_stack_trace(int v) { + return stack_trace += v; + } + long long get_steps_count() const { + return steps; + } + td::BitArray<256> get_state_hash() const; + td::BitArray<256> get_final_state_hash(int exit_code) const; + int step(); + int run(); + Stack& get_stack() { + return stack.write(); + } + const Stack& get_stack_const() const { + return *stack; + } + Ref get_stack_ref() const { + return stack; + } + Ref get_c0() const { + return cr.c[0]; + } + Ref get_c1() const { + return cr.c[1]; + } + Ref get_c2() const { + return cr.c[2]; + } + Ref get_c3() const { + return cr.c[3]; + } + Ref get_c4() const { + return cr.d[0]; + } + Ref get_c7() const { + return cr.c7; + } + Ref get_c(unsigned idx) const { + return cr.get_c(idx); + } + Ref get_d(unsigned idx) const { + return cr.get_d(idx); + } + StackEntry get(unsigned idx) const { + return cr.get(idx); + } + const VmLog& get_log() const { + return log; + } + void define_c0(Ref cont) { + cr.define_c0(std::move(cont)); + } + void set_c0(Ref cont) { + cr.set_c0(std::move(cont)); + } + void set_c1(Ref cont) { + cr.set_c1(std::move(cont)); + } + void set_c2(Ref cont) { + cr.set_c2(std::move(cont)); + } + bool set_c(unsigned idx, Ref val) { + return cr.set_c(idx, std::move(val)); + } + bool set_d(unsigned idx, Ref val) { + return cr.set_d(idx, std::move(val)); + } + void set_c4(Ref val) { + cr.set_c4(std::move(val)); + } + bool set_c7(Ref val) { + return cr.set_c7(std::move(val)); + } + bool set(unsigned idx, StackEntry val) { + return cr.set(idx, std::move(val)); + } + void set_stack(Ref new_stk) { + stack = std::move(new_stk); + } + Ref swap_stack(Ref new_stk) { + stack.swap(new_stk); + return new_stk; + } + void ensure_throw(bool cond) const { + if (!cond) { + fatal(); + } + } + void set_code(Ref _code, int _cp) { + code = std::move(_code); + force_cp(_cp); + } + Ref get_code() const { + return code; + } + void push_code() { + get_stack().push_cellslice(get_code()); + } + void adjust_cr(const ControlRegs& save) { + cr ^= save; + } + void adjust_cr(ControlRegs&& save) { + cr ^= save; + } + void preclear_cr(const ControlRegs& save) { + cr &= save; + } + int call(Ref cont); + int call(Ref cont, int pass_args, int ret_args = -1); + int jump(Ref cont); + int jump(Ref cont, int pass_args); + int ret(); + int ret(int ret_args); + int ret_alt(); + int ret_alt(int ret_args); + int repeat(Ref body, Ref after, long long count); + int again(Ref body); + int until(Ref body, Ref after); + int loop_while(Ref cond, Ref body, Ref after); + int throw_exception(int excno, StackEntry&& arg); + int throw_exception(int excno); + Ref extract_cc(int save_cr = 1, int stack_copy = -1, int cc_args = -1); + void fatal(void) const { + throw VmFatal{}; + } + int jump_to(Ref cont) { + return cont->is_unique() ? cont.unique_write().jump_w(this) : cont->jump(this); + } + static Ref convert_code_cell(Ref code_cell); + bool try_commit(); + void force_commit(); + + void set_chksig_always_succeed(bool flag) { + chksig_always_succeed = flag; + } + bool get_chksig_always_succeed() const { + return chksig_always_succeed; + } + + private: + void init_cregs(bool same_c3 = false, bool push_0 = true); +}; + +int run_vm_code(Ref _code, Ref& _stack, int flags = 0, Ref* data_ptr = nullptr, VmLog log = {}, + long long* steps = nullptr, GasLimits* gas_limits = nullptr, std::vector> libraries = {}, + Ref init_c7 = {}, Ref* actions_ptr = nullptr); +int run_vm_code(Ref _code, Stack& _stack, int flags = 0, Ref* data_ptr = nullptr, VmLog log = {}, + long long* steps = nullptr, GasLimits* gas_limits = nullptr, std::vector> libraries = {}, + Ref init_c7 = {}, Ref* actions_ptr = nullptr); + +Ref lookup_library_in(td::ConstBitPtr key, Ref lib_root); + +} // namespace vm diff --git a/submodules/ton/tonlib-src/crypto/vm/vmstate.h b/submodules/ton/tonlib-src/crypto/vm/vmstate.h index 312b662688..a81a4e78d6 100644 --- a/submodules/ton/tonlib-src/crypto/vm/vmstate.h +++ b/submodules/ton/tonlib-src/crypto/vm/vmstate.h @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once #include "common/refcnt.hpp" @@ -28,12 +28,16 @@ using td::Ref; class VmStateInterface : public td::Context { public: virtual ~VmStateInterface() = default; - virtual Ref load_library( + virtual Ref load_library( td::ConstBitPtr hash) { // may throw a dictionary exception; returns nullptr if library is not found return {}; } - virtual void register_cell_load(){}; + virtual void register_cell_load(const CellHash& cell_hash){}; virtual void register_cell_create(){}; + virtual void register_new_cell(Ref& cell){}; + virtual bool register_op(int op_units = 1) { + return true; + }; }; } // namespace vm diff --git a/submodules/ton/tonlib-src/lite-client/lite-client-common.cpp b/submodules/ton/tonlib-src/lite-client/lite-client-common.cpp index 82503faf35..5bc8ca7380 100644 --- a/submodules/ton/tonlib-src/lite-client/lite-client-common.cpp +++ b/submodules/ton/tonlib-src/lite-client/lite-client-common.cpp @@ -1,3 +1,21 @@ +/* + This file is part of TON Blockchain Library. + + TON Blockchain Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + TON Blockchain Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with TON Blockchain Library. If not, see . + + Copyright 2017-2020 Telegram Systems LLP +*/ #include "lite-client-common.h" #include "auto/tl/lite_api.hpp" @@ -9,6 +27,7 @@ using namespace std::literals::string_literals; namespace liteclient { + td::Result> deserialize_proof_chain( ton::lite_api::object_ptr f) { // deserialize proof chain @@ -75,6 +94,7 @@ td::Result> deserialize_proof_chain( LOG(DEBUG) << "deserialized a BlkProofChain of " << chain->link_count() << " links"; return std::move(chain); } + td::Ref prepare_vm_c7(ton::UnixTime now, ton::LogicalTime lt, td::Ref my_addr, const block::CurrencyCollection& balance) { td::BitArray<256> rand_seed; @@ -96,4 +116,5 @@ td::Ref prepare_vm_c7(ton::UnixTime now, ton::LogicalTime lt, td::Ref LOG(DEBUG) << "SmartContractInfo initialized with " << vm::StackEntry(tuple).to_string(); return vm::make_tuple_ref(std::move(tuple)); } + } // namespace liteclient diff --git a/submodules/ton/tonlib-src/lite-client/lite-client-common.h b/submodules/ton/tonlib-src/lite-client/lite-client-common.h index bca2c3079d..a73dab91d0 100644 --- a/submodules/ton/tonlib-src/lite-client/lite-client-common.h +++ b/submodules/ton/tonlib-src/lite-client/lite-client-common.h @@ -1,3 +1,21 @@ +/* + This file is part of TON Blockchain Library. + + TON Blockchain Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + TON Blockchain Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with TON Blockchain Library. If not, see . + + Copyright 2017-2020 Telegram Systems LLP +*/ #pragma once #include "crypto/block/block.h" @@ -5,6 +23,7 @@ #include "auto/tl/lite_api.hpp" namespace liteclient { + td::Result> deserialize_proof_chain( ton::lite_api::object_ptr f); diff --git a/submodules/ton/tonlib-src/lite-client/lite-client.cpp b/submodules/ton/tonlib-src/lite-client/lite-client.cpp index 54eb61b6ac..3dedabe2e5 100644 --- a/submodules/ton/tonlib-src/lite-client/lite-client.cpp +++ b/submodules/ton/tonlib-src/lite-client/lite-client.cpp @@ -23,7 +23,7 @@ exception statement from your version. If you delete this exception statement from all source files in the program, then also delete it here. - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "lite-client.h" @@ -55,10 +55,13 @@ #include "vm/boc.h" #include "vm/cellops.h" #include "vm/cells/MerkleProof.h" -#include "vm/continuation.h" +#include "vm/vm.h" #include "vm/cp0.h" +#include "vm/memo.h" #include "ton/ton-shard.h" #include "openssl/rand.hpp" +#include "crypto/vm/utils.h" +#include "crypto/common/util.h" #if TD_DARWIN || TD_LINUX #include @@ -140,6 +143,8 @@ void TestNode::got_result() { parse_line(std::move(data)); } if (ex_mode_ && !running_queries_ && ex_queries_.size() == 0) { + std::cout.flush(); + std::cerr.flush(); std::_Exit(0); } } @@ -177,6 +182,14 @@ bool TestNode::envelope_send_query(td::BufferSlice query, td::Promise TestNode::trivial_promise() { + return td::PromiseCreator::lambda([Self = actor_id(this)](td::Result res) { + if (res.is_error()) { + LOG(ERROR) << "error: " << res.move_as_error(); + } + }); +} + bool TestNode::register_blkid(const ton::BlockIdExt& blkid) { for (const auto& id : known_blk_ids_) { if (id == blkid) { @@ -497,7 +510,7 @@ void TestNode::run_init_queries() { get_server_version(0x100); } -std::string TestNode::get_word(char delim) { +td::Slice TestNode::get_word(char delim) { if (delim == ' ' || !delim) { skipspc(); } @@ -506,10 +519,33 @@ std::string TestNode::get_word(char delim) { ptr++; } std::swap(ptr, parse_ptr_); - return std::string{ptr, parse_ptr_}; + return td::Slice{ptr, parse_ptr_}; +} + +td::Slice TestNode::get_word_ext(const char* delims, const char* specials) { + if (delims[0] == ' ') { + skipspc(); + } + const char* ptr = parse_ptr_; + while (ptr < parse_end_ && !strchr(delims, *ptr)) { + if (specials && strchr(specials, *ptr)) { + if (ptr == parse_ptr_) { + ptr++; + } + break; + } + ptr++; + } + std::swap(ptr, parse_ptr_); + return td::Slice{ptr, parse_ptr_}; } bool TestNode::get_word_to(std::string& str, char delim) { + str = get_word(delim).str(); + return !str.empty(); +} + +bool TestNode::get_word_to(td::Slice& str, char delim) { str = get_word(delim); return !str.empty(); } @@ -545,16 +581,21 @@ bool TestNode::seekeoln() { return eoln(); } -bool TestNode::parse_account_addr(ton::WorkchainId& wc, ton::StdSmcAddress& addr) { - return block::parse_std_account_addr(get_word(), wc, addr) || set_error("cannot parse account address"); +bool TestNode::parse_account_addr(ton::WorkchainId& wc, ton::StdSmcAddress& addr, bool allow_none) { + auto word = get_word(); + if (allow_none && (word == "none" || word == "root")) { + wc = ton::workchainInvalid; + return true; + } + return block::parse_std_account_addr(word, wc, addr) || set_error("cannot parse account address"); } -bool TestNode::convert_uint64(std::string word, td::uint64& val) { +bool TestNode::convert_uint64(td::Slice word, td::uint64& val) { val = ~0ULL; if (word.empty()) { return false; } - const char* ptr = word.c_str(); + const char* ptr = word.data(); char* end = nullptr; val = std::strtoull(ptr, &end, 10); if (end == ptr + word.size()) { @@ -565,12 +606,12 @@ bool TestNode::convert_uint64(std::string word, td::uint64& val) { } } -bool TestNode::convert_int64(std::string word, td::int64& val) { +bool TestNode::convert_int64(td::Slice word, td::int64& val) { val = (~0ULL << 63); if (word.empty()) { return false; } - const char* ptr = word.c_str(); + const char* ptr = word.data(); char* end = nullptr; val = std::strtoll(ptr, &end, 10); if (end == ptr + word.size()) { @@ -581,7 +622,7 @@ bool TestNode::convert_int64(std::string word, td::int64& val) { } } -bool TestNode::convert_uint32(std::string word, td::uint32& val) { +bool TestNode::convert_uint32(td::Slice word, td::uint32& val) { td::uint64 tmp; if (convert_uint64(word, tmp) && (td::uint32)tmp == tmp) { val = (td::uint32)tmp; @@ -591,7 +632,7 @@ bool TestNode::convert_uint32(std::string word, td::uint32& val) { } } -bool TestNode::convert_int32(std::string word, td::int32& val) { +bool TestNode::convert_int32(td::Slice word, td::int32& val) { td::int64 tmp; if (convert_int64(word, tmp) && (td::int32)tmp == tmp) { val = (td::int32)tmp; @@ -609,6 +650,14 @@ bool TestNode::parse_uint32(td::uint32& val) { return convert_uint32(get_word(), val) || set_error("cannot parse 32-bit unsigned integer"); } +bool TestNode::parse_int32(td::int32& val) { + return convert_int32(get_word(), val) || set_error("cannot parse 32-bit integer"); +} + +bool TestNode::parse_int16(int& val) { + return (convert_int32(get_word(), val) && val == (td::int16)val) || set_error("cannot parse 16-bit integer"); +} + bool TestNode::set_error(td::Status error) { if (error.is_ok()) { return true; @@ -631,6 +680,10 @@ int TestNode::parse_hex_digit(int c) { return -1; } +bool TestNode::parse_hash(td::Slice str, ton::Bits256& hash) { + return str.size() == 64 && parse_hash(str.data(), hash); +} + bool TestNode::parse_hash(const char* str, ton::Bits256& hash) { unsigned char* data = hash.data(); for (int i = 0; i < 32; i++) { @@ -690,15 +743,15 @@ bool TestNode::parse_block_id_ext(std::string blkid_str, ton::BlockIdExt& blkid, } bool TestNode::parse_block_id_ext(ton::BlockIdExt& blk, bool allow_incomplete) { - return parse_block_id_ext(get_word(), blk, allow_incomplete) || set_error("cannot parse BlockIdExt"); + return parse_block_id_ext(get_word().str(), blk, allow_incomplete) || set_error("cannot parse BlockIdExt"); } bool TestNode::parse_hash(ton::Bits256& hash) { auto word = get_word(); - return (!word.empty() && parse_hash(word.c_str(), hash)) || set_error("cannot parse hash"); + return parse_hash(word, hash) || set_error("cannot parse hash"); } -bool TestNode::convert_shard_id(std::string str, ton::ShardIdFull& shard) { +bool TestNode::convert_shard_id(td::Slice str, ton::ShardIdFull& shard) { shard.workchain = ton::workchainInvalid; shard.shard = 0; auto pos = str.find(':'); @@ -729,54 +782,6 @@ bool TestNode::parse_shard_id(ton::ShardIdFull& shard) { return convert_shard_id(get_word(), shard) || set_error("cannot parse full shard identifier or prefix"); } -bool TestNode::parse_stack_value(td::Slice str, vm::StackEntry& value) { - if (str.empty() || str.size() > 65535) { - return false; - } - int l = (int)str.size(); - if (str[0] == '"') { - vm::CellBuilder cb; - if (l == 1 || str.back() != '"' || l >= 127 + 2 || !cb.store_bytes_bool(str.data() + 1, l - 2)) { - return false; - } - value = vm::StackEntry{vm::load_cell_slice_ref(cb.finalize())}; - return true; - } - if (l >= 3 && (str[0] == 'x' || str[0] == 'b') && str[1] == '{' && str.back() == '}') { - unsigned char buff[128]; - int bits = - (str[0] == 'x') - ? (int)td::bitstring::parse_bitstring_hex_literal(buff, sizeof(buff), str.begin() + 2, str.end() - 1) - : (int)td::bitstring::parse_bitstring_binary_literal(buff, sizeof(buff), str.begin() + 2, str.end() - 1); - if (bits < 0) { - return false; - } - value = - vm::StackEntry{Ref{true, vm::CellBuilder().store_bits(td::ConstBitPtr{buff}, bits).finalize()}}; - return true; - } - auto num = td::RefInt256{true}; - auto& x = num.unique_write(); - if (l >= 3 && str[0] == '0' && str[1] == 'x') { - if (x.parse_hex(str.data() + 2, l - 2) != l - 2) { - return false; - } - } else if (l >= 4 && str[0] == '-' && str[1] == '0' && str[2] == 'x') { - if (x.parse_hex(str.data() + 3, l - 3) != l - 3) { - return false; - } - x.negate().normalize(); - } else if (!l || x.parse_dec(str.data(), l) != l) { - return false; - } - value = vm::StackEntry{std::move(num)}; - return true; -} - -bool TestNode::parse_stack_value(vm::StackEntry& value) { - return parse_stack_value(td::Slice{get_word()}, value) || set_error("invalid vm stack value"); -} - bool TestNode::set_error(std::string err_msg) { return set_error(td::Status::Error(-1, err_msg)); } @@ -820,8 +825,12 @@ bool TestNode::show_help(std::string command) { "saveaccount[code|data] []\tSaves into specified file the most recent state " "(StateInit) or just the code or data of specified account; is in " "[:] format\n" - "runmethod [] ...\tRuns GET method of account " + "runmethod[full] [] ...\tRuns GET method of account " + " " "with specified parameters\n" + "dnsresolve [] []\tResolves a domain starting from root dns smart contract\n" + "dnsresolvestep [] []\tResolves a subdomain using dns smart contract " + "\n" "allshards []\tShows shard configuration from the most recent masterchain " "state or from masterchain state corresponding to \n" "getconfig [...]\tShows specified or all configuration parameters from the latest masterchain state\n" @@ -848,6 +857,11 @@ bool TestNode::show_help(std::string command) { "header\n" "byutime \tLooks up a block by workchain, shard and creation time, and " "shows its header\n" + "creatorstats [ []]\tLists block creator statistics by validator public " + "key\n" + "recentcreatorstats [ []]\tLists block creator statistics " + "updated after by validator public " + "key\n" "known\tShows the list of all known block ids\n" "privkey \tLoads a private key from file\n" "help []\tThis help\n" @@ -865,7 +879,7 @@ bool TestNode::do_parse_line() { ton::BlockSeqno seqno{}; ton::UnixTime utime{}; unsigned count{}; - std::string word = get_word(); + std::string word = get_word().str(); skipspc(); if (word == "time") { return eoln() && get_server_time(); @@ -886,21 +900,30 @@ bool TestNode::do_parse_line() { (seekeoln() ? get_account_state(workchain, addr, mc_last_id_, filename, mode) : parse_block_id_ext(blkid) && seekeoln() && get_account_state(workchain, addr, blkid, filename, mode)); - } else if (word == "runmethod") { + } else if (word == "runmethod" || word == "runmethodx" || word == "runmethodfull") { std::string method; return parse_account_addr(workchain, addr) && get_word_to(method) && (parse_block_id_ext(method, blkid) ? get_word_to(method) : (blkid = mc_last_id_).is_valid()) && - parse_run_method(workchain, addr, blkid, method); + parse_run_method(workchain, addr, blkid, method, word.size() <= 10); + } else if (word == "dnsresolve" || word == "dnsresolvestep") { + workchain = ton::workchainInvalid; + bool step = (word.size() > 10); + std::string domain; + int cat = 0; + return (!step || parse_account_addr(workchain, addr)) && get_word_to(domain) && + (parse_block_id_ext(domain, blkid) ? get_word_to(domain) : (blkid = mc_last_id_).is_valid()) && + (seekeoln() || parse_int16(cat)) && seekeoln() && + dns_resolve_start(workchain, addr, blkid, domain, cat, step); } else if (word == "allshards") { return eoln() ? get_all_shards() : (parse_block_id_ext(blkid) && seekeoln() && get_all_shards(false, blkid)); } else if (word == "saveconfig") { blkid = mc_last_id_; std::string filename; return get_word_to(filename) && (seekeoln() || parse_block_id_ext(blkid)) && seekeoln() && - get_config_params(blkid, -1, filename); + get_config_params(blkid, trivial_promise(), -1, filename); } else if (word == "getconfig" || word == "getconfigfrom") { blkid = mc_last_id_; - return (word == "getconfig" || parse_block_id_ext(blkid)) && get_config_params(blkid, 0); + return (word == "getconfig" || parse_block_id_ext(blkid)) && get_config_params(blkid, trivial_promise(), 0); } else if (word == "getblock") { return parse_block_id_ext(blkid) && seekeoln() && get_block(blkid, false); } else if (word == "dumpblock") { @@ -935,6 +958,12 @@ bool TestNode::do_parse_line() { return parse_shard_id(shard) && parse_uint32(utime) && seekeoln() && lookup_block(shard, 4, utime); } else if (word == "bylt") { return parse_shard_id(shard) && parse_lt(lt) && seekeoln() && lookup_block(shard, 2, lt); + } else if (word == "creatorstats" || word == "recentcreatorstats") { + count = 1000; + int mode = (word == "recentcreatorstats" ? 4 : 0); + return parse_block_id_ext(blkid) && (!mode || parse_uint32(utime)) && (seekeoln() || parse_uint32(count)) && + (seekeoln() || (parse_hash(hash) && (mode |= 1))) && seekeoln() && + get_creator_stats(blkid, mode, count, hash, utime); } else if (word == "known") { return eoln() && show_new_blkids(true); } else if (word == "quit" && eoln()) { @@ -1024,16 +1053,32 @@ bool TestNode::get_account_state(ton::WorkchainId workchain, ton::StdSmcAddress }); } -bool TestNode::parse_run_method(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt ref_blkid, - std::string method_name) { - std::vector params; - while (!seekeoln()) { - vm::StackEntry param; - if (!parse_stack_value(param)) { - return false; - } - params.push_back(std::move(param)); +td::int64 TestNode::compute_method_id(std::string method) { + td::int64 method_id; + if (!convert_int64(method, method_id)) { + method_id = (td::crc16(td::Slice{method}) & 0xffff) | 0x10000; } + return method_id; +} + +bool TestNode::parse_run_method(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt ref_blkid, + std::string method_name, bool ext_mode) { + auto R = vm::parse_stack_entries(td::Slice(parse_ptr_, parse_end_)); + if (R.is_error()) { + return set_error(R.move_as_error().to_string()); + } + parse_ptr_ = parse_end_; + auto P = td::PromiseCreator::lambda([](td::Result> R) { + if (R.is_error()) { + LOG(ERROR) << R.move_as_error(); + } + }); + return start_run_method(workchain, addr, ref_blkid, method_name, R.move_as_ok(), ext_mode ? 0x1f : 0, std::move(P)); +} + +bool TestNode::start_run_method(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt ref_blkid, + std::string method_name, std::vector params, int mode, + td::Promise> promise) { if (!ref_blkid.is_valid()) { return set_error("must obtain last block information before making other queries"); } @@ -1041,28 +1086,308 @@ bool TestNode::parse_run_method(ton::WorkchainId workchain, ton::StdSmcAddress a return set_error("server connection not ready"); } auto a = ton::create_tl_object(workchain, addr); - auto b = ton::serialize_tl_object(ton::create_tl_object( - ton::create_tl_lite_block_id(ref_blkid), std::move(a)), - true); - LOG(INFO) << "requesting account state for " << workchain << ":" << addr.to_hex() << " with respect to " - << ref_blkid.to_str() << " to run method " << method_name << " with " << params.size() << " parameters"; - return envelope_send_query( - std::move(b), [ Self = actor_id(this), workchain, addr, ref_blkid, method_name, - params = std::move(params) ](td::Result R) mutable { + if (!mode) { + auto b = ton::serialize_tl_object(ton::create_tl_object( + ton::create_tl_lite_block_id(ref_blkid), std::move(a)), + true); + LOG(INFO) << "requesting account state for " << workchain << ":" << addr.to_hex() << " with respect to " + << ref_blkid.to_str() << " to run method " << method_name << " with " << params.size() << " parameters"; + return envelope_send_query(std::move(b), [ + Self = actor_id(this), workchain, addr, ref_blkid, method_name, params = std::move(params), + promise = std::move(promise) + ](td::Result R) mutable { + if (R.is_error()) { + promise.set_error(R.move_as_error()); + return; + } + auto F = ton::fetch_tl_object(R.move_as_ok(), true); + if (F.is_error()) { + LOG(ERROR) << "cannot parse answer to liteServer.getAccountState"; + promise.set_error(td::Status::Error("cannot parse answer to liteServer.getAccountState")); + } else { + auto f = F.move_as_ok(); + td::actor::send_closure_later(Self, &TestNode::run_smc_method, 0, ref_blkid, ton::create_block_id(f->id_), + ton::create_block_id(f->shardblk_), std::move(f->shard_proof_), + std::move(f->proof_), std::move(f->state_), workchain, addr, method_name, + std::move(params), td::BufferSlice(), td::BufferSlice(), td::BufferSlice(), + -0x10000, std::move(promise)); + } + }); + } else { + td::int64 method_id = compute_method_id(method_name); + // set serialization limits + vm::FakeVmStateLimits fstate(1000); // limit recursive (de)serialization calls + vm::VmStateInterface::Guard guard(&fstate); + // serialize parameters + vm::CellBuilder cb; + Ref cell; + if (!(vm::Stack{params}.serialize(cb) && cb.finalize_to(cell))) { + return set_error("cannot serialize stack with get-method parameters"); + } + auto stk = vm::std_boc_serialize(std::move(cell)); + if (stk.is_error()) { + return set_error("cannot serialize stack with get-method parameters : "s + stk.move_as_error().to_string()); + } + auto b = ton::serialize_tl_object( + ton::create_tl_object(mode, ton::create_tl_lite_block_id(ref_blkid), + std::move(a), method_id, stk.move_as_ok()), + true); + LOG(INFO) << "requesting remote get-method execution for " << workchain << ":" << addr.to_hex() + << " with respect to " << ref_blkid.to_str() << " to run method " << method_name << " with " + << params.size() << " parameters"; + return envelope_send_query(std::move(b), [ + Self = actor_id(this), workchain, addr, ref_blkid, method_name, mode, params = std::move(params), + promise = std::move(promise) + ](td::Result R) mutable { + if (R.is_error()) { + promise.set_error(R.move_as_error()); + return; + } + auto F = ton::fetch_tl_object(R.move_as_ok(), true); + if (F.is_error()) { + LOG(ERROR) << "cannot parse answer to liteServer.runSmcMethod"; + promise.set_error(td::Status::Error("cannot parse answer to liteServer.runSmcMethod")); + } else { + auto f = F.move_as_ok(); + td::actor::send_closure_later(Self, &TestNode::run_smc_method, mode, ref_blkid, ton::create_block_id(f->id_), + ton::create_block_id(f->shardblk_), std::move(f->shard_proof_), + std::move(f->proof_), std::move(f->state_proof_), workchain, addr, method_name, + std::move(params), std::move(f->init_c7_), std::move(f->lib_extras_), + std::move(f->result_), f->exit_code_, std::move(promise)); + } + }); + } +} + +bool TestNode::dns_resolve_start(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt blkid, + std::string domain, int cat, int mode) { + if (domain.size() > 1023) { + return set_error("domain name too long"); + } + if (domain.size() >= 2 && domain[0] == '"' && domain.back() == '"') { + domain.erase(0, 1); + domain.pop_back(); + } + std::vector components; + std::size_t i, p = 0; + for (i = 0; i < domain.size(); i++) { + if (!domain[i] || (unsigned char)domain[i] >= 0xfe || (unsigned char)domain[i] <= ' ') { + return set_error("invalid characters in a domain name"); + } + if (domain[i] == '.') { + if (i == p) { + return set_error("domain name cannot have an empty component"); + } + components.emplace_back(domain, p, i - p); + p = i + 1; + } + } + if (i > p) { + components.emplace_back(domain, p, i - p); + } + std::string qdomain, qdomain0; + while (!components.empty()) { + qdomain += components.back(); + qdomain += '\0'; + components.pop_back(); + } + + if (!(ready_ && !client_.empty())) { + return set_error("server connection not ready"); + } + + if (workchain == ton::workchainInvalid) { + if (dns_root_queried_) { + workchain = ton::masterchainId; + addr = dns_root_; + } else { + auto P = td::PromiseCreator::lambda([this, blkid, domain, cat, mode](td::Result R) { if (R.is_error()) { - return; - } - auto F = ton::fetch_tl_object(R.move_as_ok(), true); - if (F.is_error()) { - LOG(ERROR) << "cannot parse answer to liteServer.getAccountState"; + LOG(ERROR) << "cannot obtain root dns address from configuration: " << R.move_as_error(); + } else if (dns_root_queried_) { + dns_resolve_start(ton::masterchainId, dns_root_, blkid, domain, cat, mode); } else { - auto f = F.move_as_ok(); - td::actor::send_closure_later(Self, &TestNode::run_smc_method, ref_blkid, ton::create_block_id(f->id_), - ton::create_block_id(f->shardblk_), std::move(f->shard_proof_), - std::move(f->proof_), std::move(f->state_), workchain, addr, method_name, - std::move(params)); + LOG(ERROR) << "cannot obtain root dns address from configuration parameter #4"; } }); + return get_config_params(mc_last_id_, std::move(P), 0x5000, "", {4}); + } + } + return dns_resolve_send(workchain, addr, blkid, domain, qdomain, cat, mode); +} + +bool TestNode::dns_resolve_send(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt blkid, + std::string domain, std::string qdomain, int cat, int mode) { + LOG(INFO) << "dns_resolve for '" << domain << "' category=" << cat << " mode=" << mode + << " starting from smart contract " << workchain << ":" << addr.to_hex() << " with respect to block " + << blkid.to_str(); + std::string qdomain0; + if (qdomain.size() <= 127) { + qdomain0 = qdomain; + } else { + qdomain0 = std::string{qdomain, 0, 127}; + qdomain[125] = '\xff'; + qdomain[126] = '\x0'; + } + vm::CellBuilder cb; + Ref cell; + if (!(cb.store_bytes_bool(td::Slice(qdomain0)) && cb.finalize_to(cell))) { + return set_error("cannot store domain name into slice"); + } + std::vector params; + params.emplace_back(vm::load_cell_slice_ref(std::move(cell))); + params.emplace_back(td::make_refint(cat)); + auto P = td::PromiseCreator::lambda([this, workchain, addr, blkid, domain, qdomain, cat, + mode](td::Result> R) { + if (R.is_error()) { + LOG(ERROR) << R.move_as_error(); + return; + } + auto S = R.move_as_ok(); + if (S.size() < 2 || !S[S.size() - 2].is_int() || !(S.back().is_cell() || S.back().is_null())) { + LOG(ERROR) << "dnsresolve did not return a value of type (int,cell)"; + return; + } + auto cell = S.back().as_cell(); + S.pop_back(); + auto x = S.back().as_int(); + S.clear(); + if (!x->signed_fits_bits(32)) { + LOG(ERROR) << "invalid integer result of dnsresolve (" << x << ")"; + return; + } + return dns_resolve_finish(workchain, addr, blkid, domain, qdomain, cat, mode, (int)x->to_long(), std::move(cell)); + }); + return start_run_method(workchain, addr, blkid, "dnsresolve", std::move(params), 0x1f, std::move(P)); +} + +bool TestNode::show_dns_record(std::ostream& os, int cat, Ref value, bool raw_dump) { + if (raw_dump) { + bool ok = show_dns_record(os, cat, value, false); + if (!ok) { + os << "cannot parse dns record; raw value: "; + vm::load_cell_slice(value).print_rec(print_limit_, os); + } + return ok; + } + if (value.is_null()) { + os << "(null)"; + return true; + } + // block::gen::t_DNSRecord.print_ref(print_limit_, os, value); + if (!block::gen::t_DNSRecord.validate_ref(value)) { + return false; + } + block::gen::t_DNSRecord.print_ref(print_limit_, os, value); + auto cs = vm::load_cell_slice(value); + auto tag = block::gen::t_DNSRecord.get_tag(cs); + ton::WorkchainId wc; + ton::StdSmcAddress addr; + switch (tag) { + case block::gen::DNSRecord::dns_adnl_address: { + block::gen::DNSRecord::Record_dns_adnl_address rec; + if (tlb::unpack_exact(cs, rec)) { + os << "\n\tadnl address " << rec.adnl_addr.to_hex() << " = " << td::adnl_id_encode(rec.adnl_addr, true); + } + break; + } + case block::gen::DNSRecord::dns_smc_address: { + block::gen::DNSRecord::Record_dns_smc_address rec; + if (tlb::unpack_exact(cs, rec) && block::tlb::t_MsgAddressInt.extract_std_address(rec.smc_addr, wc, addr)) { + os << "\tsmart contract " << wc << ":" << addr.to_hex() << " = " << block::StdAddress{wc, addr}.rserialize(true); + } + break; + } + case block::gen::DNSRecord::dns_next_resolver: { + block::gen::DNSRecord::Record_dns_next_resolver rec; + if (tlb::unpack_exact(cs, rec) && block::tlb::t_MsgAddressInt.extract_std_address(rec.resolver, wc, addr)) { + os << "\tnext resolver " << wc << ":" << addr.to_hex() << " = " << block::StdAddress{wc, addr}.rserialize(true); + } + break; + } + } + return true; +} + +void TestNode::dns_resolve_finish(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt blkid, + std::string domain, std::string qdomain, int cat, int mode, int used_bits, + Ref value) { + if (used_bits <= 0) { + td::TerminalIO::out() << "domain '" << domain << "' not found" << std::endl; + return; + } + if ((used_bits & 7) || (unsigned)used_bits > 8 * std::min(qdomain.size(), 126)) { + LOG(ERROR) << "too many bits used (" << used_bits << " out of " << qdomain.size() * 8 << ")"; + return; + } + int pos = (used_bits >> 3); + if (qdomain[pos - 1]) { + LOG(ERROR) << "domain split not at a component boundary"; + return; + } + bool end = ((std::size_t)pos == qdomain.size()); + if (!end) { + LOG(INFO) << "partial information obtained"; + if (value.is_null()) { + td::TerminalIO::out() << "domain '" << domain << "' not found: no next resolver" << std::endl; + return; + } + Ref nx_address; + ton::WorkchainId nx_wc; + ton::StdSmcAddress nx_addr; + if (!(block::gen::t_DNSRecord.cell_unpack_dns_next_resolver(value, nx_address) && + block::tlb::t_MsgAddressInt.extract_std_address(std::move(nx_address), nx_wc, nx_addr))) { + LOG(ERROR) << "cannot parse next resolver info for " << domain.substr(qdomain.size() - pos); + std::ostringstream out; + vm::load_cell_slice(value).print_rec(print_limit_, out); + td::TerminalIO::err() << out.str() << std::endl; + return; + } + LOG(INFO) << "next resolver is " << nx_wc << ":" << nx_addr.to_hex(); + if ((mode & 1)) { + return; // no recursive resolving + } + if (!(dns_resolve_send(nx_wc, nx_addr, blkid, domain, qdomain.substr(pos), cat, mode))) { + LOG(ERROR) << "cannot send next dns query"; + return; + } + LOG(INFO) << "recursive dns query to '" << domain.substr(qdomain.size() - pos) << "' sent"; + return; + } + auto out = td::TerminalIO::out(); + out << "Result for domain '" << domain << "' category " << cat << (cat ? "" : " (all categories)") << std::endl; + try { + if (value.not_null()) { + std::ostringstream os0; + vm::load_cell_slice(value).print_rec(print_limit_, os0); + out << "raw data: " << os0.str() << std::endl; + } + if (!cat) { + vm::Dictionary dict{value, 16}; + if (!dict.check_for_each([this, &out](Ref cs, td::ConstBitPtr key, int n) { + CHECK(n == 16); + int x = (int)key.get_int(16); + if (cs.is_null() || cs->size_ext() != 0x10000) { + out << "category #" << x << " : value is not a reference" << std::endl; + return false; + } + std::ostringstream os; + (void)show_dns_record(os, x, cs->prefetch_ref(), true); + out << "category #" << x << " : " << os.str() << std::endl; + return true; + })) { + out << "invalid dns record dictionary" << std::endl; + } + } else { + std::ostringstream os; + (void)show_dns_record(os, cat, value, true); + out << "category #" << cat << " : " << os.str() << std::endl; + } + } catch (vm::VmError& err) { + LOG(ERROR) << "vm error while traversing dns resolve result: " << err.get_msg(); + } catch (vm::VmVirtError& err) { + LOG(ERROR) << "vm virtualization error while traversing dns resolve result: " << err.get_msg(); + } } bool TestNode::get_one_transaction(ton::BlockIdExt blkid, ton::WorkchainId workchain, ton::StdSmcAddress addr, @@ -1150,8 +1475,8 @@ void TestNode::got_account_state(ton::BlockIdExt ref_blk, ton::BlockIdExt blk, t if (info.root.not_null()) { out << "account state is "; std::ostringstream outp; - block::gen::t_Account.print_ref(outp, info.root); - vm::load_cell_slice(info.root).print_rec(outp); + block::gen::t_Account.print_ref(print_limit_, outp, info.root); + vm::load_cell_slice(info.root).print_rec(print_limit_, outp); out << outp.str(); out << "last transaction lt = " << info.last_trans_lt << " hash = " << info.last_trans_hash.to_hex() << std::endl; block::gen::Account::Record_account acc; @@ -1223,87 +1548,152 @@ void TestNode::got_account_state(ton::BlockIdExt ref_blk, ton::BlockIdExt blk, t } } -void TestNode::run_smc_method(ton::BlockIdExt ref_blk, ton::BlockIdExt blk, ton::BlockIdExt shard_blk, +void TestNode::run_smc_method(int mode, ton::BlockIdExt ref_blk, ton::BlockIdExt blk, ton::BlockIdExt shard_blk, td::BufferSlice shard_proof, td::BufferSlice proof, td::BufferSlice state, ton::WorkchainId workchain, ton::StdSmcAddress addr, std::string method, - std::vector params) { - LOG(INFO) << "got account state for " << workchain << ":" << addr.to_hex() << " with respect to blocks " - << blk.to_str() << (shard_blk == blk ? "" : std::string{" and "} + shard_blk.to_str()); - block::AccountState account_state; - account_state.blk = blk; - account_state.shard_blk = shard_blk; - account_state.shard_proof = std::move(shard_proof); - account_state.proof = std::move(proof); - account_state.state = std::move(state); - auto r_info = account_state.validate(ref_blk, block::StdAddress(workchain, addr)); - if (r_info.is_error()) { - LOG(ERROR) << r_info.error().message(); - return; - } + std::vector params, td::BufferSlice remote_c7, + td::BufferSlice remote_libs, td::BufferSlice remote_result, int remote_exit_code, + td::Promise> promise) { + LOG(INFO) << "got (partial) account state with mode=" << mode << " for " << workchain << ":" << addr.to_hex() + << " with respect to blocks " << blk.to_str() + << (shard_blk == blk ? "" : std::string{" and "} + shard_blk.to_str()); auto out = td::TerminalIO::out(); - auto info = r_info.move_as_ok(); - if (info.root.is_null()) { - LOG(ERROR) << "account state of " << workchain << ":" << addr.to_hex() << " is empty (cannot run method `" << method - << "`)"; - return; - } - block::gen::Account::Record_account acc; - block::gen::AccountStorage::Record store; - block::CurrencyCollection balance; - if (!(tlb::unpack_cell(info.root, acc) && tlb::csr_unpack(acc.storage, store) && - balance.validate_unpack(store.balance))) { - LOG(ERROR) << "error unpacking account state"; - return; - } - int tag = block::gen::t_AccountState.get_tag(*store.state); - switch (tag) { - case block::gen::AccountState::account_uninit: - LOG(ERROR) << "account " << workchain << ":" << addr.to_hex() << " not initialized yet (cannot run any methods)"; + try { + block::AccountState account_state; + account_state.blk = blk; + account_state.shard_blk = shard_blk; + account_state.shard_proof = std::move(shard_proof); + account_state.proof = std::move(proof); + LOG(DEBUG) << "serialized state is " << state.size() << " bytes"; + LOG(DEBUG) << "serialized remote c7 is " << remote_c7.size() << " bytes"; + account_state.state = std::move(state); + account_state.is_virtualized = (mode > 0); + auto r_info = account_state.validate(ref_blk, block::StdAddress(workchain, addr)); + if (r_info.is_error()) { + LOG(ERROR) << r_info.error().message(); + promise.set_error(r_info.move_as_error()); return; - case block::gen::AccountState::account_frozen: - LOG(ERROR) << "account " << workchain << ":" << addr.to_hex() << " frozen (cannot run any methods)"; + } + auto out = td::TerminalIO::out(); + auto info = r_info.move_as_ok(); + if (info.root.is_null()) { + LOG(ERROR) << "account state of " << workchain << ":" << addr.to_hex() << " is empty (cannot run method `" + << method << "`)"; + promise.set_error(td::Status::Error(PSLICE() << "account state of " << workchain << ":" << addr.to_hex() + << " is empty (cannot run method `" << method << "`)")); return; - } - CHECK(store.state.write().fetch_ulong(1) == 1); // account_init$1 _:StateInit = AccountState; - block::gen::StateInit::Record state_init; - CHECK(tlb::csr_unpack(store.state, state_init)); - auto code = state_init.code->prefetch_ref(); - auto data = state_init.data->prefetch_ref(); - auto stack = td::make_ref(std::move(params)); - td::int64 method_id; - if (!convert_int64(method, method_id)) { - method_id = (td::crc16(td::Slice{method}) & 0xffff) | 0x10000; - } - stack.write().push_smallint(method_id); - { - std::ostringstream os; - os << "arguments: "; - stack->dump(os); - out << os.str(); - } - long long gas_limit = vm::GasLimits::infty; - // OstreamLogger ostream_logger(ctx.error_stream); - // auto log = create_vm_log(ctx.error_stream ? &ostream_logger : nullptr); - vm::GasLimits gas{gas_limit}; - LOG(DEBUG) << "creating VM"; - vm::VmState vm{code, std::move(stack), gas, 1, data, vm::VmLog()}; - vm.set_c7(liteclient::prepare_vm_c7(info.gen_utime, info.gen_lt, acc.addr, balance)); // tuple with SmartContractInfo - // vm.incr_stack_trace(1); // enable stack dump after each step - LOG(INFO) << "starting VM to run method `" << method << "` (" << method_id << ") of smart contract " << workchain - << ":" << addr.to_hex(); - int exit_code = ~vm.run(); - LOG(DEBUG) << "VM terminated with exit code " << exit_code; - if (exit_code != 0) { - LOG(ERROR) << "VM terminated with error code " << exit_code; - out << "result: error " << exit_code << std::endl; - return; - } - stack = vm.get_stack_ref(); - { - std::ostringstream os; - os << "result: "; - stack->dump(os); - out << os.str(); + } + if (false) { + // DEBUG (dump state) + std::ostringstream os; + vm::CellSlice{vm::NoVm(), info.true_root}.print_rec(print_limit_, os); + out << "dump of account state (proof): " << os.str() << std::endl; + } + // set deserialization limits + vm::FakeVmStateLimits fstate(1000); // limit recursive (de)serialization calls + vm::VmStateInterface::Guard guard(&fstate); + if (false && remote_c7.size()) { + // DEBUG (dump remote_c7) + auto r_c7 = vm::std_boc_deserialize(remote_c7).move_as_ok(); + std::ostringstream os; + vm::StackEntry val; + bool ok = val.deserialize(r_c7); + val.dump(os); + // os << std::endl; + // block::gen::t_VmStackValue.print_ref(print_limit_, os, r_c7); + // os << std::endl; + // vm::CellSlice{vm::NoVmOrd(), r_c7}.print_rec(print_limit_, os); + out << "remote_c7 (deserialized=" << ok << "): " << os.str() << std::endl; + } + block::gen::Account::Record_account acc; + block::gen::AccountStorage::Record store; + block::CurrencyCollection balance; + if (!(tlb::unpack_cell(info.root, acc) && tlb::csr_unpack(acc.storage, store) && + balance.validate_unpack(store.balance))) { + LOG(ERROR) << "error unpacking account state"; + promise.set_error(td::Status::Error("error unpacking account state")); + return; + } + int tag = block::gen::t_AccountState.get_tag(*store.state); + switch (tag) { + case block::gen::AccountState::account_uninit: + LOG(ERROR) << "account " << workchain << ":" << addr.to_hex() + << " not initialized yet (cannot run any methods)"; + return; + case block::gen::AccountState::account_frozen: + LOG(ERROR) << "account " << workchain << ":" << addr.to_hex() << " frozen (cannot run any methods)"; + return; + } + CHECK(store.state.write().fetch_ulong(1) == 1); // account_init$1 _:StateInit = AccountState; + block::gen::StateInit::Record state_init; + CHECK(tlb::csr_unpack(store.state, state_init)); + auto code = state_init.code->prefetch_ref(); + auto data = state_init.data->prefetch_ref(); + auto stack = td::make_ref(std::move(params)); + td::int64 method_id = compute_method_id(method); + stack.write().push_smallint(method_id); + { + std::ostringstream os; + os << "arguments: "; + stack->dump(os, 3); + out << os.str(); + } + long long gas_limit = vm::GasLimits::infty; + // OstreamLogger ostream_logger(ctx.error_stream); + // auto log = create_vm_log(ctx.error_stream ? &ostream_logger : nullptr); + vm::GasLimits gas{gas_limit}; + LOG(DEBUG) << "creating VM"; + vm::VmState vm{code, std::move(stack), gas, 1, data, vm::VmLog()}; + vm.set_c7(liteclient::prepare_vm_c7(info.gen_utime, info.gen_lt, td::make_ref(acc.addr->clone()), + balance)); // tuple with SmartContractInfo + // vm.incr_stack_trace(1); // enable stack dump after each step + LOG(INFO) << "starting VM to run method `" << method << "` (" << method_id << ") of smart contract " << workchain + << ":" << addr.to_hex(); + int exit_code = ~vm.run(); + LOG(DEBUG) << "VM terminated with exit code " << exit_code; + if (mode > 0) { + LOG(DEBUG) << "remote VM exit code is " << remote_exit_code; + } + if (exit_code != 0) { + LOG(ERROR) << "VM terminated with error code " << exit_code; + out << "result: error " << exit_code << std::endl; + promise.set_error(td::Status::Error(PSLICE() << "VM terminated with non-zero exit code " << exit_code)); + return; + } + stack = vm.get_stack_ref(); + { + std::ostringstream os; + os << "result: "; + stack->dump(os, 3); + out << os.str(); + } + if (mode & 4) { + if (remote_result.empty()) { + out << "remote result: , exit code " << remote_exit_code; + } else { + auto res = vm::std_boc_deserialize(std::move(remote_result)); + if (res.is_error()) { + LOG(ERROR) << "cannot deserialize remote VM result boc: " << res.move_as_error(); + return; + } + auto cs = vm::load_cell_slice(res.move_as_ok()); + Ref remote_stack; + if (!(vm::Stack::deserialize_to(cs, remote_stack, 0) && cs.empty_ext())) { + LOG(ERROR) << "remote VM result boc cannot be deserialized as a VmStack"; + return; + } + std::ostringstream os; + os << "remote result (not to be trusted): "; + remote_stack->dump(os, 3); + out << os.str(); + } + } + out.flush(); + promise.set_result(stack->extract_contents()); + } catch (vm::VmVirtError& err) { + out << "virtualization error while parsing runSmcMethod result: " << err.get_msg(); + } catch (vm::VmError& err) { + out << "error while parsing runSmcMethod result: " << err.get_msg(); } } @@ -1386,8 +1776,8 @@ void TestNode::got_one_transaction(ton::BlockIdExt req_blkid, ton::BlockIdExt bl } else { out << "transaction is "; std::ostringstream outp; - block::gen::t_Transaction.print_ref(outp, root); - vm::load_cell_slice(root).print_rec(outp); + block::gen::t_Transaction.print_ref(print_limit_, outp, root, 0); + vm::load_cell_slice(root).print_rec(print_limit_, outp); out << outp.str(); } } @@ -1512,8 +1902,8 @@ void TestNode::got_last_transactions(std::vector blkids, td::Bu out << "transaction #" << c << " from block " << blkid.to_str() << (dump ? " is " : "\n"); if (dump) { std::ostringstream outp; - block::gen::t_Transaction.print_ref(outp, info.transaction); - vm::load_cell_slice(info.transaction).print_rec(outp); + block::gen::t_Transaction.print_ref(print_limit_, outp, info.transaction); + vm::load_cell_slice(info.transaction).print_rec(print_limit_, outp); out << outp.str(); } block::gen::Transaction::Record trans; @@ -1641,8 +2031,8 @@ void TestNode::got_all_shards(ton::BlockIdExt blk, td::BufferSlice proof, td::Bu auto out = td::TerminalIO::out(); out << "shard configuration is "; std::ostringstream outp; - block::gen::t_ShardHashes.print_ref(outp, root); - vm::load_cell_slice(root).print_rec(outp); + block::gen::t_ShardHashes.print_ref(print_limit_, outp, root); + vm::load_cell_slice(root).print_rec(print_limit_, outp); out << outp.str(); block::ShardConfig sh_conf; if (!sh_conf.unpack(vm::load_cell_slice_ref(root))) { @@ -1665,26 +2055,35 @@ void TestNode::got_all_shards(ton::BlockIdExt blk, td::BufferSlice proof, td::Bu show_new_blkids(); } -bool TestNode::get_config_params(ton::BlockIdExt blkid, int mode, std::string filename) { - std::vector params; - if (mode >= 0 && !seekeoln()) { +bool TestNode::get_config_params(ton::BlockIdExt blkid, td::Promise do_after, int mode, std::string filename, + std::vector params) { + if (mode < 0) { + mode = 0x8000; + } + if (!(mode & 0x9000) && !seekeoln()) { mode |= 0x1000; while (!seekeoln()) { int x; if (!convert_int32(get_word(), x)) { + do_after.set_error(td::Status::Error("integer configuration parameter id expected")); return set_error("integer configuration parameter id expected"); } params.push_back(x); } } if (!(ready_ && !client_.empty())) { + do_after.set_error(td::Status::Error("integer configuration parameter id expected")); return set_error("server connection not ready"); } if (!blkid.is_masterchain_ext()) { + do_after.set_error(td::Status::Error("integer configuration parameter id expected")); return set_error("only masterchain blocks contain configuration"); } + if (blkid == mc_last_id_) { + mode |= 0x2000; + } auto params_copy = params; - auto b = (mode & 0x3000) == 0x1000 + auto b = (mode & 0x1000) ? ton::serialize_tl_object(ton::create_tl_object( 0, ton::create_tl_lite_block_id(blkid), std::move(params_copy)), true) @@ -1693,9 +2092,11 @@ bool TestNode::get_config_params(ton::BlockIdExt blkid, int mode, std::string fi true); LOG(INFO) << "requesting " << params.size() << " configuration parameters with respect to masterchain block " << blkid.to_str(); - return envelope_send_query(std::move(b), [ Self = actor_id(this), mode, filename, blkid, - params = std::move(params) ](td::Result R) mutable { + return envelope_send_query(std::move(b), [ + Self = actor_id(this), mode, filename, blkid, params = std::move(params), do_after = std::move(do_after) + ](td::Result R) mutable { if (R.is_error()) { + do_after.set_error(R.move_as_error()); return; } auto F = ton::fetch_tl_object(R.move_as_ok(), true); @@ -1705,13 +2106,14 @@ bool TestNode::get_config_params(ton::BlockIdExt blkid, int mode, std::string fi auto f = F.move_as_ok(); td::actor::send_closure_later(Self, &TestNode::got_config_params, blkid, ton::create_block_id(f->id_), std::move(f->state_proof_), std::move(f->config_proof_), mode, filename, - std::move(params)); + std::move(params), std::move(do_after)); } }); } void TestNode::got_config_params(ton::BlockIdExt req_blkid, ton::BlockIdExt blkid, td::BufferSlice state_proof, - td::BufferSlice cfg_proof, int mode, std::string filename, std::vector params) { + td::BufferSlice cfg_proof, int mode, std::string filename, std::vector params, + td::Promise do_after) { LOG(INFO) << "got configuration parameters"; if (!blkid.is_masterchain_ext()) { LOG(ERROR) << "reference block " << blkid.to_str() << " for the configuration is not a valid masterchain block"; @@ -1734,7 +2136,7 @@ void TestNode::got_config_params(ton::BlockIdExt req_blkid, ton::BlockIdExt blki return; } auto config = res.move_as_ok(); - if (mode < 0) { + if (mode & 0x8000) { auto F = vm::std_boc_serialize(config->get_root_cell(), 2); if (F.is_error()) { LOG(ERROR) << "cannot serialize configuration: " << F.move_as_error().to_string(); @@ -1760,26 +2162,32 @@ void TestNode::got_config_params(ton::BlockIdExt req_blkid, ton::BlockIdExt blki } else { std::ostringstream os; if (i >= 0) { - block::gen::ConfigParam{i}.print_ref(os, value); + block::gen::ConfigParam{i}.print_ref(print_limit_, os, value); os << std::endl; } - vm::load_cell_slice(value).print_rec(os); + vm::load_cell_slice(value).print_rec(print_limit_, os); out << os.str() << std::endl; + if (i == 4 && (mode & 0x2000)) { + register_config_param4(value); + } } } } else { - config->foreach_config_param([&out](int i, Ref value) { + config->foreach_config_param([this, &out, mode](int i, Ref value) { out << "ConfigParam(" << i << ") = "; if (value.is_null()) { out << "(null)\n"; } else { std::ostringstream os; if (i >= 0) { - block::gen::ConfigParam{i}.print_ref(os, value); + block::gen::ConfigParam{i}.print_ref(print_limit_, os, value); os << std::endl; } - vm::load_cell_slice(value).print_rec(os); + vm::load_cell_slice(value).print_rec(print_limit_, os); out << os.str() << std::endl; + if (i == 4 && (mode & 0x2000)) { + register_config_param4(value); + } } return true; }); @@ -1789,6 +2197,25 @@ void TestNode::got_config_params(ton::BlockIdExt req_blkid, ton::BlockIdExt blki } catch (vm::VmVirtError& err) { LOG(ERROR) << "virtualization error while traversing configuration: " << err.get_msg(); } + do_after.set_result(td::Unit()); +} + +bool TestNode::register_config_param4(Ref value) { + if (value.is_null()) { + return false; + } + vm::CellSlice cs{vm::NoVmOrd(), std::move(value)}; + ton::StdSmcAddress addr; + if (cs.size_ext() == 256 && cs.fetch_bits_to(addr)) { + dns_root_queried_ = true; + if (dns_root_ != addr) { + dns_root_ = addr; + LOG(INFO) << "dns root set to -1:" << addr.to_hex(); + } + return true; + } else { + return false; + } } bool TestNode::get_block(ton::BlockIdExt blkid, bool dump) { @@ -1882,8 +2309,8 @@ void TestNode::got_block(ton::BlockIdExt blkid, td::BufferSlice data, bool dump) auto out = td::TerminalIO::out(); out << "block contents is "; std::ostringstream outp; - block::gen::t_Block.print_ref(outp, root); - vm::load_cell_slice(root).print_rec(outp); + block::gen::t_Block.print_ref(print_limit_, outp, root); + vm::load_cell_slice(root).print_rec(print_limit_, outp); out << outp.str(); show_block_header(blkid, std::move(root), 0xffff); } else { @@ -1938,8 +2365,8 @@ void TestNode::got_state(ton::BlockIdExt blkid, ton::RootHash root_hash, ton::Fi auto out = td::TerminalIO::out(); out << "shard state contents is "; std::ostringstream outp; - block::gen::t_ShardState.print_ref(outp, root); - vm::load_cell_slice(root).print_rec(outp); + block::gen::t_ShardState.print_ref(print_limit_, outp, root); + vm::load_cell_slice(root).print_rec(print_limit_, outp); out << outp.str(); show_state_header(blkid, std::move(root), 0xffff); } else { @@ -2073,8 +2500,8 @@ void TestNode::got_block_header(ton::BlockIdExt blkid, td::BufferSlice data, int } auto root = res.move_as_ok(); std::ostringstream outp; - vm::CellSlice cs{vm::NoVm{}, root}; - cs.print_rec(outp); + vm::CellSlice cs{vm::NoVm(), root}; + cs.print_rec(print_limit_, outp); td::TerminalIO::out() << outp.str(); try { auto virt_root = vm::MerkleProof::virtualize(root, 1); @@ -2173,6 +2600,107 @@ void TestNode::got_block_proof(ton::BlockIdExt from, ton::BlockIdExt to, int mod show_new_blkids(); } +bool TestNode::get_creator_stats(ton::BlockIdExt blkid, int mode, unsigned req_count, ton::Bits256 start_after, + ton::UnixTime min_utime) { + if (!(ready_ && !client_.empty())) { + return set_error("server connection not ready"); + } + if (!blkid.is_masterchain_ext()) { + return set_error("only masterchain blocks contain block creator statistics"); + } + if (!(mode & 1)) { + start_after.set_zero(); + } + auto b = ton::serialize_tl_object(ton::create_tl_object( + mode, ton::create_tl_lite_block_id(blkid), req_count, start_after, min_utime), + true); + LOG(INFO) << "requesting up to " << req_count << " block creator stats records with respect to masterchain block " + << blkid.to_str() << " starting from validator public key " << start_after.to_hex() << " created after " + << min_utime << " (mode=" << mode << ")"; + return envelope_send_query(std::move(b), [ Self = actor_id(this), mode, blkid, req_count, start_after, + min_utime ](td::Result R) { + if (R.is_error()) { + return; + } + auto F = ton::fetch_tl_object(R.move_as_ok(), true); + if (F.is_error()) { + LOG(ERROR) << "cannot parse answer to liteServer.getValidatorStats"; + } else { + auto f = F.move_as_ok(); + td::actor::send_closure_later(Self, &TestNode::got_creator_stats, blkid, ton::create_block_id(f->id_), mode, + f->mode_, start_after, min_utime, std::move(f->state_proof_), + std::move(f->data_proof_), f->count_, req_count, f->complete_); + } + }); +} + +void TestNode::got_creator_stats(ton::BlockIdExt req_blkid, ton::BlockIdExt blkid, int req_mode, int mode, + td::Bits256 start_after, ton::UnixTime min_utime, td::BufferSlice state_proof, + td::BufferSlice data_proof, int count, int req_count, bool complete) { + LOG(INFO) << "got answer to getValidatorStats query: " << count << " records out of " << req_count << ", " + << (complete ? "complete" : "incomplete"); + if (!blkid.is_masterchain_ext()) { + LOG(ERROR) << "reference block " << blkid.to_str() + << " for block creator statistics is not a valid masterchain block"; + return; + } + if (count > req_count) { + LOG(ERROR) << "obtained " << count << " answers to getValidatorStats query, but only " << req_count + << " were requested"; + return; + } + if (blkid != req_blkid) { + LOG(ERROR) << "answer to getValidatorStats refers to masterchain block " << blkid.to_str() + << " different from requested " << req_blkid.to_str(); + return; + } + auto R = block::check_extract_state_proof(blkid, state_proof.as_slice(), data_proof.as_slice()); + if (R.is_error()) { + LOG(ERROR) << "masterchain state proof for " << blkid.to_str() << " is invalid : " << R.move_as_error().to_string(); + return; + } + bool allow_eq = (mode & 3) != 1; + ton::Bits256 key{start_after}; + std::ostringstream os; + try { + auto dict = block::get_block_create_stats_dict(R.move_as_ok()); + if (!dict) { + LOG(ERROR) << "cannot extract BlockCreateStats from mc state"; + return; + } + for (int i = 0; i < count + (int)complete; i++) { + auto v = dict->lookup_nearest_key(key, true, allow_eq); + if (v.is_null()) { + if (i != count) { + LOG(ERROR) << "could fetch only " << i << " CreatorStats entries out of " << count + << " declared in answer to getValidatorStats"; + return; + } + break; + } + block::DiscountedCounter mc_cnt, shard_cnt; + if (!block::unpack_CreatorStats(std::move(v), mc_cnt, shard_cnt)) { + LOG(ERROR) << "invalid CreatorStats record with key " << key.to_hex(); + return; + } + if (mc_cnt.modified_since(min_utime) || shard_cnt.modified_since(min_utime)) { + os << key.to_hex() << " mc_cnt:" << mc_cnt << " shard_cnt:" << shard_cnt << std::endl; + } + allow_eq = false; + } + if (complete) { + os << "(complete)" << std::endl; + } else { + os << "(incomplete, repeat query from " << key.to_hex() << " )" << std::endl; + } + td::TerminalIO::out() << os.str(); + } catch (vm::VmError& err) { + LOG(ERROR) << "error while traversing block creator stats: " << err.get_msg(); + } catch (vm::VmVirtError& err) { + LOG(ERROR) << "virtualization error while traversing block creator stats: " << err.get_msg(); + } +} + int main(int argc, char* argv[]) { SET_VERBOSITY_LEVEL(verbosity_INFO); td::set_default_failure_signal_handler(); @@ -2205,6 +2733,11 @@ int main(int argc, char* argv[]) { td::actor::send_closure(x, &TestNode::set_db_root, fname.str()); return td::Status::OK(); }); + p.add_option('L', "print-limit", "sets maximum count of recursively printed objects", [&](td::Slice arg) { + auto plimit = td::to_integer(arg); + td::actor::send_closure(x, &TestNode::set_print_limit, plimit); + return plimit >= 0 ? td::Status::OK() : td::Status::Error("printing limit must be non-negative"); + }); p.add_option('v', "verbosity", "set verbosity level", [&](td::Slice arg) { verbosity = td::to_integer(arg); SET_VERBOSITY_LEVEL(VERBOSITY_NAME(FATAL) + verbosity); @@ -2257,7 +2790,7 @@ int main(int argc, char* argv[]) { }); #endif - vm::init_op_cp0(); + vm::init_op_cp0(true); // enable vm debug td::actor::Scheduler scheduler({2}); diff --git a/submodules/ton/tonlib-src/lite-client/lite-client.h b/submodules/ton/tonlib-src/lite-client/lite-client.h index 36830e8d5b..7ebaaf1781 100644 --- a/submodules/ton/tonlib-src/lite-client/lite-client.h +++ b/submodules/ton/tonlib-src/lite-client/lite-client.h @@ -23,7 +23,7 @@ exception statement from your version. If you delete this exception statement from all source files in the program, then also delete it here. - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once #include "adnl/adnl-ext-client.h" @@ -50,6 +50,7 @@ class TestNode : public td::actor::Actor { bool readline_enabled_ = true; bool server_ok_ = false; td::int32 liteserver_idx_ = -1; + int print_limit_ = 1024; bool ready_ = false; bool inited_ = false; @@ -66,6 +67,9 @@ class TestNode : public td::actor::Actor { ton::BlockIdExt last_block_id_, last_state_id_; td::BufferSlice last_block_data_, last_state_data_; + ton::StdSmcAddress dns_root_; + bool dns_root_queried_{false}; + std::string line_; const char *parse_ptr_, *parse_end_; td::Status error_; @@ -93,6 +97,9 @@ class TestNode : public td::actor::Actor { }; void run_init_queries(); + char cur() const { + return *parse_ptr_; + } bool get_server_time(); bool get_server_version(int mode = 0); void got_server_version(td::Result res, int mode); @@ -114,16 +121,32 @@ class TestNode : public td::actor::Actor { td::BufferSlice shard_proof, td::BufferSlice proof, td::BufferSlice state, ton::WorkchainId workchain, ton::StdSmcAddress addr, std::string filename, int mode); bool parse_run_method(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt ref_blkid, - std::string method_name); - void run_smc_method(ton::BlockIdExt ref_blk, ton::BlockIdExt blk, ton::BlockIdExt shard_blk, + std::string method_name, bool ext_mode); + bool start_run_method(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt ref_blkid, + std::string method_name, std::vector params, int mode, + td::Promise> promise); + void run_smc_method(int mode, ton::BlockIdExt ref_blk, ton::BlockIdExt blk, ton::BlockIdExt shard_blk, td::BufferSlice shard_proof, td::BufferSlice proof, td::BufferSlice state, ton::WorkchainId workchain, ton::StdSmcAddress addr, std::string method, - std::vector params); + std::vector params, td::BufferSlice remote_c7, td::BufferSlice remote_libs, + td::BufferSlice remote_result, int remote_exit_code, + td::Promise> promise); + bool register_config_param4(Ref value); + bool dns_resolve_start(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt blkid, std::string domain, + int cat, int mode); + bool dns_resolve_send(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt blkid, std::string domain, + std::string qdomain, int cat, int mode); + void dns_resolve_finish(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt blkid, + std::string domain, std::string qdomain, int cat, int mode, int used_bits, + Ref value); + bool show_dns_record(std::ostream& os, int cat, Ref value, bool raw_dump); bool get_all_shards(bool use_last = true, ton::BlockIdExt blkid = {}); void got_all_shards(ton::BlockIdExt blk, td::BufferSlice proof, td::BufferSlice data); - bool get_config_params(ton::BlockIdExt blkid, int mode = 0, std::string filename = ""); + bool get_config_params(ton::BlockIdExt blkid, td::Promise do_after, int mode = 0, std::string filename = "", + std::vector params = {}); void got_config_params(ton::BlockIdExt req_blkid, ton::BlockIdExt blkid, td::BufferSlice state_proof, - td::BufferSlice cfg_proof, int mode, std::string filename, std::vector params); + td::BufferSlice cfg_proof, int mode, std::string filename, std::vector params, + td::Promise do_after); bool get_block(ton::BlockIdExt blk, bool dump = false); void got_block(ton::BlockIdExt blkid, td::BufferSlice data, bool dump); bool get_state(ton::BlockIdExt blk, bool dump = false); @@ -150,10 +173,18 @@ class TestNode : public td::actor::Actor { std::vector trans, td::BufferSlice proof); bool get_block_proof(ton::BlockIdExt from, ton::BlockIdExt to, int mode); void got_block_proof(ton::BlockIdExt from, ton::BlockIdExt to, int mode, td::BufferSlice res); + bool get_creator_stats(ton::BlockIdExt blkid, int mode, unsigned req_count, ton::Bits256 start_after, + ton::UnixTime min_utime); + void got_creator_stats(ton::BlockIdExt req_blkid, ton::BlockIdExt blkid, int req_mode, int mode, + td::Bits256 start_after, ton::UnixTime min_utime, td::BufferSlice state_proof, + td::BufferSlice data_proof, int count, int req_count, bool complete); + // parser bool do_parse_line(); bool show_help(std::string command); - std::string get_word(char delim = ' '); + td::Slice get_word(char delim = ' '); + td::Slice get_word_ext(const char* delims, const char* specials = nullptr); bool get_word_to(std::string& str, char delim = ' '); + bool get_word_to(td::Slice& str, char delim = ' '); int skipspc(); std::string get_line_tail(bool remove_spaces = true) const; bool eoln() const; @@ -161,25 +192,31 @@ class TestNode : public td::actor::Actor { bool set_error(td::Status error); bool set_error(std::string err_msg); void show_context() const; - bool parse_account_addr(ton::WorkchainId& wc, ton::StdSmcAddress& addr); + bool parse_account_addr(ton::WorkchainId& wc, ton::StdSmcAddress& addr, bool allow_none = false); static int parse_hex_digit(int c); static bool parse_hash(const char* str, ton::Bits256& hash); - static bool convert_uint64(std::string word, td::uint64& val); - static bool convert_int64(std::string word, td::int64& val); - static bool convert_uint32(std::string word, td::uint32& val); - static bool convert_int32(std::string word, td::int32& val); - static bool convert_shard_id(std::string str, ton::ShardIdFull& shard); + static bool parse_hash(td::Slice str, ton::Bits256& hash); + static bool convert_uint64(td::Slice word, td::uint64& val); + static bool convert_int64(td::Slice word, td::int64& val); + static bool convert_uint32(td::Slice word, td::uint32& val); + static bool convert_int32(td::Slice word, td::int32& val); + static bool convert_shard_id(td::Slice str, ton::ShardIdFull& shard); + static td::int64 compute_method_id(std::string method); bool parse_hash(ton::Bits256& hash); bool parse_lt(ton::LogicalTime& lt); bool parse_uint32(td::uint32& val); + bool parse_int32(td::int32& val); + bool parse_int16(int& val); bool parse_shard_id(ton::ShardIdFull& shard); bool parse_block_id_ext(ton::BlockIdExt& blkid, bool allow_incomplete = false); bool parse_block_id_ext(std::string blk_id_string, ton::BlockIdExt& blkid, bool allow_incomplete = false) const; bool parse_stack_value(td::Slice str, vm::StackEntry& value); bool parse_stack_value(vm::StackEntry& value); + bool parse_stack_values(std::vector& values); bool register_blkid(const ton::BlockIdExt& blkid); bool show_new_blkids(bool all = false); bool complete_blkid(ton::BlockId partial_blkid, ton::BlockIdExt& complete_blkid) const; + td::Promise trivial_promise(); public: void conn_ready() { @@ -222,6 +259,11 @@ class TestNode : public td::actor::Actor { fail_timeout_ = ts; alarm_timestamp().relax(fail_timeout_); } + void set_print_limit(int plimit) { + if (plimit >= 0) { + print_limit_ = plimit; + } + } void add_cmd(td::BufferSlice data) { ex_mode_ = true; ex_queries_.push_back(std::move(data)); diff --git a/submodules/ton/tonlib-src/tdactor/benchmark/benchmark.cpp b/submodules/ton/tonlib-src/tdactor/benchmark/benchmark.cpp index 442bb84c61..deddcb22ce 100644 --- a/submodules/ton/tonlib-src/tdactor/benchmark/benchmark.cpp +++ b/submodules/ton/tonlib-src/tdactor/benchmark/benchmark.cpp @@ -23,7 +23,7 @@ exception statement from your version. If you delete this exception statement from all source files in the program, then also delete it here. - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "third_party/FAAArrayQueue.h" #include "third_party/HazardPointers.h" @@ -56,7 +56,10 @@ extern "C" { #include "td/utils/Random.h" #include "td/utils/Slice.h" #include "td/utils/Status.h" +#include "td/utils/StealingQueue.h" +#include "td/utils/ThreadSafeCounter.h" #include "td/utils/UInt.h" +#include "td/utils/VectorQueue.h" #include #include @@ -796,10 +799,13 @@ class MpmcQueueBenchmark : public td::Benchmark { std::vector m_threads(m_); auto impl = std::make_unique(n_ + m_ + 1); size_t thread_id = 0; + td::ThreadSafeCounter counter; + CHECK(counter.sum() == 0); for (auto &thread : m_threads) { thread = td::thread([&, thread_id] { while (true) { size_t value = impl->pop(thread_id); + counter.add(-static_cast(value)); if (!value) { break; } @@ -811,6 +817,7 @@ class MpmcQueueBenchmark : public td::Benchmark { thread = td::thread([&, thread_id] { for (int i = 0; i < n / n_; i++) { impl->push(static_cast(i + 1), thread_id); + counter.add(i + 1); } }); thread_id++; @@ -818,7 +825,10 @@ class MpmcQueueBenchmark : public td::Benchmark { for (auto &thread : n_threads) { thread.join(); } - for (int i = 0; i < m_; i++) { + while (counter.sum() != 0) { + td::this_thread::yield(); + } + for (int i = 0; i < m_ + n_ + 1; i++) { impl->push(0, thread_id); } for (auto &thread : m_threads) { @@ -832,6 +842,62 @@ class MpmcQueueBenchmark : public td::Benchmark { int m_; }; +template +class MpmcQueueBenchmark2 : public td::Benchmark { + public: + MpmcQueueBenchmark2(int n, int k) : n_(n), k_(k) { + } + std::string get_description() const override { + return PSTRING() << "MpmcQueueBenchmark2 " << n_ << " " << k_ << " " << Impl::get_description(); + } + + void run(int n) override { + std::vector n_threads(n_); + auto impl = std::make_unique(n_ + 1); + size_t thread_id = 0; + std::atomic left{k_}; + + for (int i = 0; i < k_; i++) { + impl->push(n, thread_id); + } + + for (auto &thread : n_threads) { + thread = td::thread([&, thread_id] { + while (true) { + size_t value = impl->pop(thread_id); + if (value > 1) { + impl->push(value - 1, thread_id); + } + if (value == 1) { + left--; + } + if (!value) { + break; + } + } + }); + thread_id++; + } + + while (left.load() != 0) { + td::this_thread::yield(); + } + + for (int i = 0; i < n_ + 1; i++) { + impl->push(0, thread_id); + } + + for (auto &thread : n_threads) { + thread.join(); + } + impl.reset(); + } + + private: + int n_; + int k_; +}; + class Cheat { public: explicit Cheat(size_t thread_n) : impl_(static_cast(thread_n)) { @@ -959,26 +1025,95 @@ std::string CfQueueT, Cell>::get_description() { template class MoodyQueue { public: - explicit MoodyQueue(size_t) { + explicit MoodyQueue(size_t n) { + for (size_t i = 0; i < n; i++) { + p.push_back(moodycamel::ProducerToken(q)); + c.push_back(moodycamel::ConsumerToken(q)); + } } static std::string get_description() { return "moodycamel queue"; } - void push(Value v, size_t) { - q.enqueue(v); + void push(Value v, size_t tid) { + q.enqueue(p[tid], v); } - Value pop(size_t) { + Value pop(size_t tid) { Value res; - while (!q.try_dequeue(res)) { + while (!q.try_dequeue(c[tid], res)) { } + //q.wait_dequeue(c[tid], res); return res; } - bool try_pop(Value &value, size_t) { - return q.try_dequeue(value); + bool try_pop(Value &value, size_t tid) { + return q.try_dequeue(c[tid], value); } private: moodycamel::ConcurrentQueue q; + std::vector p; + std::vector c; +}; + +struct Sem { + public: + void post() { + if (++cnt_ == 0) { + { + std::unique_lock lk(mutex_); + } + cnd_.notify_one(); + } + } + void wait(int cnt = 1) { + auto was = cnt_.fetch_sub(cnt); + if (was >= cnt) { + return; + } + std::unique_lock lk(mutex_); + cnd_.wait(lk, [&] { return cnt_ >= 0; }); + } + + private: + std::mutex mutex_; + std::condition_variable cnd_; + std::atomic cnt_{0}; +}; + +template +class MagicQueue { + public: + explicit MagicQueue(size_t n) : n_(n), qs_(n_ - 1), pos_{0} { + } + static std::string get_description() { + return "magic queue"; + } + void push(Value v, size_t tid) { + if (v == 0) { + return; + } + + if (tid + 1 == n_) { + qs_[pos_].push(v); + pos_ = (pos_ + 1) % (n_ - 1); + } else { + qs_[tid].push(v); + } + } + Value pop(size_t tid) { + CHECK(tid + 1 != n_); + if (qs_[tid].empty()) { + return 0; + } + return qs_[tid].pop(); + } + bool try_pop(Value &value, size_t) { + UNREACHABLE(); + } + + private: + size_t n_; + std::vector> qs_; + size_t pos_; }; #if TG_LCR_QUEUE @@ -1110,65 +1245,155 @@ class WaitQueue { static std::string get_description() { return "Wait + " + Q::get_description(); } - explicit WaitQueue(size_t threads_n) : impl(threads_n) { + + explicit WaitQueue(size_t threads_n) : impl(threads_n), slots(threads_n) { + for (size_t i = 0; i < threads_n; i++) { + waiter.init_slot(slots[i].slot, static_cast(i)); + } } + T pop(size_t thread_id) { T res; - int yields = 0; - while (!impl.try_pop(res, thread_id)) { - yields = waiter.wait(yields, static_cast(thread_id)); + while (true) { + if (slots[thread_id].local_queue.try_pop(res)) { + break; + } + if (impl.try_pop(res, thread_id)) { + break; + } + waiter.wait(slots[thread_id].slot); } - waiter.stop_wait(yields, static_cast(thread_id)); + waiter.stop_wait(slots[thread_id].slot); + //LOG(ERROR) << "GOT"; return res; } + + void push_local(T value, size_t thread_id) { + auto o_value = slots[thread_id].local_queue.push(value); + if (o_value) { + push(o_value.unwrap, thread_id); + } + } + void push(T value, size_t thread_id) { - impl.push(std::move(value), static_cast(thread_id)); + impl.push(value, static_cast(thread_id)); waiter.notify(); } private: W waiter; Q impl; + struct Slot { + typename W::Slot slot; + td::actor::core::LocalQueue local_queue; + }; + std::vector slots; +}; +template +class StealingWaitQueue { + public: + static std::string get_description() { + return "StealWait + " + Q::get_description(); + } + + explicit StealingWaitQueue(size_t threads_n) : impl(threads_n), slots(threads_n) { + for (size_t i = 0; i < threads_n; i++) { + waiter.init_slot(slots[i].slot, static_cast(i)); + } + } + + T pop(size_t thread_id) { + T res; + while (true) { + if (slots[thread_id].stealing_queue.local_pop(res)) { + break; + } + if (slots[thread_id].local_queue.try_pop(res)) { + break; + } + if (impl.try_pop(res, thread_id)) { + break; + } + + bool ok = false; + for (size_t i = 1; i < slots.size(); i++) { + auto pos = (i + thread_id) % slots.size(); + if (slots[thread_id].stealing_queue.steal(res, slots[pos].stealing_queue)) { + ok = true; + break; + } + } + if (ok) { + break; + } + waiter.wait(slots[thread_id].slot); + } + waiter.stop_wait(slots[thread_id].slot); + //LOG(ERROR) << "GOT"; + return res; + } + + void push_local(T value, size_t thread_id) { + auto o_value = slots[thread_id].local_queue.push(value); + if (o_value) { + push(o_value.unwrap, thread_id); + } + } + + void push(T value, size_t thread_id) { + slots[thread_id].stealing_queue.local_push(value, + [&](auto value) { impl.push(value, static_cast(thread_id)); }); + waiter.notify(); + } + + private: + W waiter; + Q impl; + struct Slot { + typename W::Slot slot; + td::actor::core::LocalQueue local_queue; + td::StealingQueue stealing_queue; + }; + std::vector slots; }; void run_queue_bench(int n, int m) { - bench(MpmcQueueBenchmark, td::MpmcWaiter, size_t>>(n, m), 2); - bench(MpmcQueueBenchmark>(n, m), 2); - bench(MpmcQueueBenchmark>(n, m), 2); - bench(MpmcQueueBenchmark(n, m), 2); - bench(MpmcQueueBenchmark>>(n, m), 2); - bench(MpmcQueueBenchmark>>(n, m), 2); - bench(MpmcQueueBenchmark>(n, m), 2); + bench(MpmcQueueBenchmark>(n, m), 2); + bench(MpmcQueueBenchmark, td::MpmcEagerWaiter, size_t>>(n, m), 2); + bench(MpmcQueueBenchmark, td::MpmcSleepyWaiter, size_t>>(n, m), 2); + bench(MpmcQueueBenchmark, td::MpmcEagerWaiter, size_t>>(n, m), 2); + bench(MpmcQueueBenchmark, td::MpmcSleepyWaiter, size_t>>(n, m), 2); + //bench(MpmcQueueBenchmark>(n, m), 2); + //bench(MpmcQueueBenchmark>(n, m), 2); + //bench(MpmcQueueBenchmark(n, m), 2); + //bench(MpmcQueueBenchmark>>(n, m), 2); + //bench(MpmcQueueBenchmark>>(n, m), 2); + //bench(MpmcQueueBenchmark>(n, m), 2); + //bench(MpmcQueueBenchmark(n, m), 2); #if TG_LCR_QUEUE bench(MpmcQueueBenchmark>>(n, m), 2); #endif } +void run_queue_bench2(int n, int k) { + bench(MpmcQueueBenchmark2, td::MpmcSleepyWaiter, size_t>>(n, k), 2); + bench(MpmcQueueBenchmark2, td::MpmcEagerWaiter, size_t>>(n, k), 2); + bench(MpmcQueueBenchmark2>(n, k), 2); + bench(MpmcQueueBenchmark2>(n, k), 2); + bench(MpmcQueueBenchmark2, td::MpmcEagerWaiter, size_t>>(n, k), 2); + bench(MpmcQueueBenchmark2, td::MpmcSleepyWaiter, size_t>>(n, k), 2); + //bench(MpmcQueueBenchmark2>(n, k), 2); + //bench(MpmcQueueBenchmark2>(n, k), 2); + //bench(MpmcQueueBenchmark2(n, k), 2); + //bench(MpmcQueueBenchmark2>>(n, k), 2); + //bench(MpmcQueueBenchmark2>>(n, k), 2); + //bench(MpmcQueueBenchmark2>(n, k), 2); -struct Sem { - public: - void post() { - if (++cnt_ == 0) { - { - std::unique_lock lk(mutex_); - } - cnd_.notify_one(); - } - } - void wait(int cnt = 1) { - auto was = cnt_.fetch_sub(cnt); - if (was >= cnt) { - return; - } - std::unique_lock lk(mutex_); - cnd_.wait(lk, [&] { return cnt_ >= 0; }); - } - - private: - std::mutex mutex_; - std::condition_variable cnd_; - std::atomic cnt_{0}; -}; + //bench(MpmcQueueBenchmark(n, m), 2); +#if TG_LCR_QUEUE + bench(MpmcQueueBenchmark2>>(n, k), 2); +#endif +} class ChainedSpawn : public td::Benchmark { public: @@ -1415,17 +1640,18 @@ class YieldMany : public td::Benchmark { int main(int argc, char **argv) { if (argc > 1) { if (argv[1][0] == 'a') { - bench_n(MpmcQueueBenchmark>(1, 1), 1 << 26); + bench_n(MpmcQueueBenchmark2, td::MpmcEagerWaiter, size_t>>(50, 1), 1 << 26); + //bench_n(MpmcQueueBenchmark>(1, 1), 1 << 26); //bench_n(MpmcQueueBenchmark(1, 40), 1 << 20); //bench_n(MpmcQueueBenchmark>>(1, 40), 1 << 20); } else { - bench_n(MpmcQueueBenchmark>(1, 1), 1 << 26); + bench_n(MpmcQueueBenchmark2, td::MpmcSleepyWaiter, size_t>>(50, 1), 1 << 26); + //bench_n(MpmcQueueBenchmark>(1, 1), 1 << 26); //bench_n(MpmcQueueBenchmark>>(1, 40), 1 << 20); //bench_n(MpmcQueueBenchmark>>(1, 1), 1 << 26); } return 0; } - bench(YieldMany(false)); bench(YieldMany(true)); bench(SpawnMany(false)); @@ -1436,6 +1662,22 @@ int main(int argc, char **argv) { bench(ChainedSpawnInplace(true)); bench(ChainedSpawn(false)); bench(ChainedSpawn(true)); + + run_queue_bench(10, 10); + run_queue_bench(10, 1); + run_queue_bench(1, 10); + run_queue_bench(1, 1); + run_queue_bench(2, 10); + run_queue_bench(2, 2); + run_queue_bench(10, 1); + + run_queue_bench2(50, 1); + run_queue_bench2(50, 2); + run_queue_bench2(1, 100); + run_queue_bench2(1, 1000); + run_queue_bench2(10, 2); + run_queue_bench2(10, 1000); + return 0; bench(ActorDummyQuery()); @@ -1466,16 +1708,5 @@ int main(int argc, char **argv) { bench(CalcHashSha256Benchmark>>>()); bench(CalcHashSha256Benchmark>>>()); - run_queue_bench(1, 10); - run_queue_bench(1, 1); - run_queue_bench(2, 10); - run_queue_bench(2, 2); - run_queue_bench(10, 10); - - run_queue_bench(2, 2); - run_queue_bench(1, 10); - run_queue_bench(10, 1); - run_queue_bench(10, 10); - return 0; } diff --git a/submodules/ton/tonlib-src/tdactor/benchmark/third_party/MoodyCamelQueue.h b/submodules/ton/tonlib-src/tdactor/benchmark/third_party/MoodyCamelQueue.h index 936a2f5fcd..1c7cf80143 100644 --- a/submodules/ton/tonlib-src/tdactor/benchmark/third_party/MoodyCamelQueue.h +++ b/submodules/ton/tonlib-src/tdactor/benchmark/third_party/MoodyCamelQueue.h @@ -269,17 +269,17 @@ static inline thread_id_t thread_id() { namespace moodycamel { namespace details { #if defined(__GNUC__) -inline bool likely(bool x) { +static inline bool(likely)(bool x) { return __builtin_expect((x), true); } -inline bool unlikely(bool x) { +static inline bool(unlikely)(bool x) { return __builtin_expect((x), false); } #else -inline bool likely(bool x) { +static inline bool(likely)(bool x) { return x; } -inline bool unlikely(bool x) { +static inline bool(unlikely)(bool x) { return x; } #endif @@ -300,8 +300,8 @@ struct const_numeric_max { : static_cast(-1); }; -#if defined(__GNUC__) && !defined(__clang__) -typedef ::max_align_t std_max_align_t; // GCC forgot to add it to std:: for a while +#if defined(__GLIBCXX__) +typedef ::max_align_t std_max_align_t; // libstdc++ forgot to add it to std:: for a while #else typedef std::max_align_t std_max_align_t; // Others (e.g. MSVC) insist it can *only* be accessed via std:: #endif @@ -377,8 +377,8 @@ struct ConcurrentQueueDefaultTraits { static const size_t MAX_SUBQUEUE_SIZE = details::const_numeric_max::value; #ifndef MCDBGQ_USE_RELACY -// Memory allocation can be customized if needed. -// malloc should return nullptr on failure, and handle alignment like std::malloc. + // Memory allocation can be customized if needed. + // malloc should return nullptr on failure, and handle alignment like std::malloc. #if defined(malloc) || defined(free) // Gah, this is 2015, stop defining macros that break standard code already! // Work around malloc/free being special macros: @@ -1140,7 +1140,7 @@ class ConcurrentQueue { // If there was at least one non-empty queue but it appears empty at the time // we try to dequeue from it, we need to make sure every queue's been tried if (nonEmptyCount > 0) { - if (details::likely(best->dequeue(item))) { + if ((details::likely)(best->dequeue(item))) { return true; } for (auto ptr = producerListTail.load(std::memory_order_acquire); ptr != nullptr; ptr = ptr->next_prod()) { @@ -1335,7 +1335,10 @@ class ConcurrentQueue { private: friend struct ProducerToken; friend struct ConsumerToken; + struct ExplicitProducer; friend struct ExplicitProducer; + struct ImplicitProducer; + friend struct ImplicitProducer; friend class ConcurrentQueueTests; enum AllocationMode { CanAlloc, CannotAlloc }; @@ -1380,7 +1383,7 @@ class ConcurrentQueue { } auto prodCount = producerCount.load(std::memory_order_relaxed); auto globalOffset = globalExplicitConsumerOffset.load(std::memory_order_relaxed); - if (details::unlikely(token.desiredProducer == nullptr)) { + if ((details::unlikely)(token.desiredProducer == nullptr)) { // Aha, first time we're dequeueing anything. // Figure out our local position // Note: offset is from start, not end, but we're traversing from end -- subtract from count first @@ -1442,7 +1445,7 @@ class ConcurrentQueue { FreeList& operator=(FreeList const&) MOODYCAMEL_DELETE_FUNCTION; inline void add(N* node) { -#if MCDBGQ_NOLOCKFREE_FREELIST +#ifdef MCDBGQ_NOLOCKFREE_FREELIST debug::DebugLock lock(mutex); #endif // We know that the should-be-on-freelist bit is 0 at this point, so it's safe to @@ -1455,7 +1458,7 @@ class ConcurrentQueue { } inline N* try_get() { -#if MCDBGQ_NOLOCKFREE_FREELIST +#ifdef MCDBGQ_NOLOCKFREE_FREELIST debug::DebugLock lock(mutex); #endif auto head = freeListHead.load(std::memory_order_acquire); @@ -1529,7 +1532,7 @@ class ConcurrentQueue { static const std::uint32_t REFS_MASK = 0x7FFFFFFF; static const std::uint32_t SHOULD_BE_ON_FREELIST = 0x80000000; -#if MCDBGQ_NOLOCKFREE_FREELIST +#ifdef MCDBGQ_NOLOCKFREE_FREELIST debug::DebugMutex mutex; #endif }; @@ -1548,7 +1551,7 @@ class ConcurrentQueue { , freeListNext(nullptr) , shouldBeOnFreeList(false) , dynamicallyAllocated(true) { -#if MCDBGQ_TRACKMEM +#ifdef MCDBGQ_TRACKMEM owner = nullptr; #endif } @@ -1679,14 +1682,14 @@ class ConcurrentQueue { std::atomic shouldBeOnFreeList; bool dynamicallyAllocated; // Perhaps a better name for this would be 'isNotPartOfInitialBlockPool' -#if MCDBGQ_TRACKMEM +#ifdef MCDBGQ_TRACKMEM void* owner; #endif }; static_assert(std::alignment_of::value >= std::alignment_of::value, "Internal error: Blocks must be at least as aligned as the type they are wrapping"); -#if MCDBGQ_TRACKMEM +#ifdef MCDBGQ_TRACKMEM public: struct MemStats; @@ -1756,7 +1759,7 @@ class ConcurrentQueue { ConcurrentQueue* parent; protected: -#if MCDBGQ_TRACKMEM +#ifdef MCDBGQ_TRACKMEM friend struct MemStats; #endif }; @@ -1902,7 +1905,7 @@ class ConcurrentQueue { if (newBlock == nullptr) { return false; } -#if MCDBGQ_TRACKMEM +#ifdef MCDBGQ_TRACKMEM newBlock->owner = this; #endif newBlock->ConcurrentQueue::Block::template reset_empty(); @@ -1916,7 +1919,7 @@ class ConcurrentQueue { ++pr_blockIndexSlotsUsed; } - if (!MOODYCAMEL_NOEXCEPT_CTOR(T, U, new (nullptr) T(std::forward(element)))) { + if (!MOODYCAMEL_NOEXCEPT_CTOR(T, U, new ((T*)nullptr) T(std::forward(element)))) { // The constructor may throw. We want the element not to appear in the queue in // that case (without corrupting the queue): MOODYCAMEL_TRY { @@ -1941,7 +1944,7 @@ class ConcurrentQueue { blockIndex.load(std::memory_order_relaxed)->front.store(pr_blockIndexFront, std::memory_order_release); pr_blockIndexFront = (pr_blockIndexFront + 1) & (pr_blockIndexSize - 1); - if (!MOODYCAMEL_NOEXCEPT_CTOR(T, U, new (nullptr) T(std::forward(element)))) { + if (!MOODYCAMEL_NOEXCEPT_CTOR(T, U, new ((T*)nullptr) T(std::forward(element)))) { this->tailIndex.store(newTailIndex, std::memory_order_release); return true; } @@ -1985,13 +1988,14 @@ class ConcurrentQueue { // incremented after dequeueOptimisticCount -- this is enforced in the `else` block below), and since we now // have a version of dequeueOptimisticCount that is at least as recent as overcommit (due to the release upon // incrementing dequeueOvercommit and the acquire above that synchronizes with it), overcommit <= myDequeueCount. - assert(overcommit <= myDequeueCount); + // However, we can't assert this since both dequeueOptimisticCount and dequeueOvercommit may (independently) + // overflow; in such a case, though, the logic still holds since the difference between the two is maintained. // Note that we reload tail here in case it changed; it will be the same value as before or greater, since // this load is sequenced after (happens after) the earlier load above. This is supported by read-read // coherency (as defined in the standard), explained here: http://en.cppreference.com/w/cpp/atomic/memory_order tail = this->tailIndex.load(std::memory_order_acquire); - if (details::likely(details::circular_less_than(myDequeueCount - overcommit, tail))) { + if ((details::likely)(details::circular_less_than(myDequeueCount - overcommit, tail))) { // Guaranteed to be at least one element to dequeue! // Get the index. Note that since there's guaranteed to be at least one element, this @@ -2033,10 +2037,10 @@ class ConcurrentQueue { } } guard = {block, index}; - element = std::move(el); + element = std::move(el); // NOLINT } else { - element = std::move(el); - el.~T(); + element = std::move(el); // NOLINT + el.~T(); // NOLINT block->ConcurrentQueue::Block::template set_empty(index); } @@ -2119,7 +2123,7 @@ class ConcurrentQueue { return false; } -#if MCDBGQ_TRACKMEM +#ifdef MCDBGQ_TRACKMEM newBlock->owner = this; #endif newBlock->ConcurrentQueue::Block::template set_all_empty(); @@ -2151,7 +2155,8 @@ class ConcurrentQueue { block = block->next; } - if (MOODYCAMEL_NOEXCEPT_CTOR(T, decltype(*itemFirst), new (nullptr) T(details::deref_noexcept(itemFirst)))) { + if (MOODYCAMEL_NOEXCEPT_CTOR(T, decltype(*itemFirst), + new ((T*)nullptr) T(details::deref_noexcept(itemFirst)))) { blockIndex.load(std::memory_order_relaxed) ->front.store((pr_blockIndexFront - 1) & (pr_blockIndexSize - 1), std::memory_order_release); } @@ -2172,7 +2177,8 @@ class ConcurrentQueue { if (details::circular_less_than(newTailIndex, stopIndex)) { stopIndex = newTailIndex; } - if (MOODYCAMEL_NOEXCEPT_CTOR(T, decltype(*itemFirst), new (nullptr) T(details::deref_noexcept(itemFirst)))) { + if (MOODYCAMEL_NOEXCEPT_CTOR(T, decltype(*itemFirst), + new ((T*)nullptr) T(details::deref_noexcept(itemFirst)))) { while (currentTailIndex != stopIndex) { new ((*this->tailBlock)[currentTailIndex++]) T(*itemFirst++); } @@ -2186,9 +2192,10 @@ class ConcurrentQueue { // may only define a (noexcept) move constructor, and so calls to the // cctor will not compile, even if they are in an if branch that will never // be executed - new ((*this->tailBlock)[currentTailIndex]) T( - details::nomove_if<(bool)!MOODYCAMEL_NOEXCEPT_CTOR( - T, decltype(*itemFirst), new (nullptr) T(details::deref_noexcept(itemFirst)))>::eval(*itemFirst)); + new ((*this->tailBlock)[currentTailIndex]) + T(details::nomove_if<(bool)!MOODYCAMEL_NOEXCEPT_CTOR( + T, decltype(*itemFirst), + new ((T*)nullptr) T(details::deref_noexcept(itemFirst)))>::eval(*itemFirst)); ++currentTailIndex; ++itemFirst; } @@ -2236,7 +2243,7 @@ class ConcurrentQueue { this->tailBlock = this->tailBlock->next; } - if (!MOODYCAMEL_NOEXCEPT_CTOR(T, decltype(*itemFirst), new (nullptr) T(details::deref_noexcept(itemFirst))) && + if (!MOODYCAMEL_NOEXCEPT_CTOR(T, decltype(*itemFirst), new ((T*)nullptr) T(details::deref_noexcept(itemFirst))) && firstAllocatedBlock != nullptr) { blockIndex.load(std::memory_order_relaxed) ->front.store((pr_blockIndexFront - 1) & (pr_blockIndexSize - 1), std::memory_order_release); @@ -2257,7 +2264,7 @@ class ConcurrentQueue { std::atomic_thread_fence(std::memory_order_acquire); auto myDequeueCount = this->dequeueOptimisticCount.fetch_add(desiredCount, std::memory_order_relaxed); - assert(overcommit <= myDequeueCount); + ; tail = this->tailIndex.load(std::memory_order_acquire); auto actualCount = static_cast(tail - (myDequeueCount - overcommit)); @@ -2418,7 +2425,7 @@ class ConcurrentQueue { private: #endif -#if MCDBGQ_TRACKMEM +#ifdef MCDBGQ_TRACKMEM friend struct MemStats; #endif }; @@ -2500,7 +2507,7 @@ class ConcurrentQueue { (MAX_SUBQUEUE_SIZE == 0 || MAX_SUBQUEUE_SIZE - BLOCK_SIZE < currentTailIndex - head))) { return false; } -#if MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX debug::DebugLock lock(mutex); #endif // Find out where we'll be inserting this block in the block index @@ -2516,12 +2523,12 @@ class ConcurrentQueue { idxEntry->value.store(nullptr, std::memory_order_relaxed); return false; } -#if MCDBGQ_TRACKMEM +#ifdef MCDBGQ_TRACKMEM newBlock->owner = this; #endif newBlock->ConcurrentQueue::Block::template reset_empty(); - if (!MOODYCAMEL_NOEXCEPT_CTOR(T, U, new (nullptr) T(std::forward(element)))) { + if (!MOODYCAMEL_NOEXCEPT_CTOR(T, U, new ((T*)nullptr) T(std::forward(element)))) { // May throw, try to insert now before we publish the fact that we have this new block MOODYCAMEL_TRY { new ((*newBlock)[currentTailIndex]) T(std::forward(element)); @@ -2539,7 +2546,7 @@ class ConcurrentQueue { this->tailBlock = newBlock; - if (!MOODYCAMEL_NOEXCEPT_CTOR(T, U, new (nullptr) T(std::forward(element)))) { + if (!MOODYCAMEL_NOEXCEPT_CTOR(T, U, new ((T*)nullptr) T(std::forward(element)))) { this->tailIndex.store(newTailIndex, std::memory_order_release); return true; } @@ -2562,9 +2569,8 @@ class ConcurrentQueue { std::atomic_thread_fence(std::memory_order_acquire); index_t myDequeueCount = this->dequeueOptimisticCount.fetch_add(1, std::memory_order_relaxed); - assert(overcommit <= myDequeueCount); tail = this->tailIndex.load(std::memory_order_acquire); - if (details::likely(details::circular_less_than(myDequeueCount - overcommit, tail))) { + if ((details::likely)(details::circular_less_than(myDequeueCount - overcommit, tail))) { index_t index = this->headIndex.fetch_add(1, std::memory_order_acq_rel); // Determine which block the element is in @@ -2575,7 +2581,7 @@ class ConcurrentQueue { auto& el = *((*block)[index]); if (!MOODYCAMEL_NOEXCEPT_ASSIGN(T, T&&, element = std::move(el))) { -#if MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX // Note: Acquiring the mutex with every dequeue instead of only when a block // is released is very sub-optimal, but it is, after all, purely debug code. debug::DebugLock lock(producer->mutex); @@ -2595,14 +2601,14 @@ class ConcurrentQueue { } } guard = {block, index, entry, this->parent}; - element = std::move(el); + element = std::move(el); // NOLINT } else { - element = std::move(el); - el.~T(); + element = std::move(el); // NOLINT + el.~T(); // NOLINT if (block->ConcurrentQueue::Block::template set_empty(index)) { { -#if MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX debug::DebugLock lock(mutex); #endif // Add the block back into the global free pool (and remove from block index) @@ -2642,7 +2648,7 @@ class ConcurrentQueue { ((startTailIndex - 1) & ~static_cast(BLOCK_SIZE - 1)); index_t currentTailIndex = (startTailIndex - 1) & ~static_cast(BLOCK_SIZE - 1); if (blockBaseDiff > 0) { -#if MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX debug::DebugLock lock(mutex); #endif do { @@ -2679,7 +2685,7 @@ class ConcurrentQueue { return false; } -#if MCDBGQ_TRACKMEM +#ifdef MCDBGQ_TRACKMEM newBlock->owner = this; #endif newBlock->ConcurrentQueue::Block::template reset_empty(); @@ -2714,16 +2720,18 @@ class ConcurrentQueue { if (details::circular_less_than(newTailIndex, stopIndex)) { stopIndex = newTailIndex; } - if (MOODYCAMEL_NOEXCEPT_CTOR(T, decltype(*itemFirst), new (nullptr) T(details::deref_noexcept(itemFirst)))) { + if (MOODYCAMEL_NOEXCEPT_CTOR(T, decltype(*itemFirst), + new ((T*)nullptr) T(details::deref_noexcept(itemFirst)))) { while (currentTailIndex != stopIndex) { new ((*this->tailBlock)[currentTailIndex++]) T(*itemFirst++); } } else { MOODYCAMEL_TRY { while (currentTailIndex != stopIndex) { - new ((*this->tailBlock)[currentTailIndex]) T( - details::nomove_if<(bool)!MOODYCAMEL_NOEXCEPT_CTOR( - T, decltype(*itemFirst), new (nullptr) T(details::deref_noexcept(itemFirst)))>::eval(*itemFirst)); + new ((*this->tailBlock)[currentTailIndex]) + T(details::nomove_if<(bool)!MOODYCAMEL_NOEXCEPT_CTOR( + T, decltype(*itemFirst), + new ((T*)nullptr) T(details::deref_noexcept(itemFirst)))>::eval(*itemFirst)); ++currentTailIndex; ++itemFirst; } @@ -2788,7 +2796,6 @@ class ConcurrentQueue { std::atomic_thread_fence(std::memory_order_acquire); auto myDequeueCount = this->dequeueOptimisticCount.fetch_add(desiredCount, std::memory_order_relaxed); - assert(overcommit <= myDequeueCount); tail = this->tailIndex.load(std::memory_order_acquire); auto actualCount = static_cast(tail - (myDequeueCount - overcommit)); @@ -2843,7 +2850,7 @@ class ConcurrentQueue { if (block->ConcurrentQueue::Block::template set_many_empty( blockStartIndex, static_cast(endIndex - blockStartIndex))) { -#if MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX debug::DebugLock lock(mutex); #endif entry->value.store(nullptr, std::memory_order_relaxed); @@ -2865,7 +2872,7 @@ class ConcurrentQueue { if (block->ConcurrentQueue::Block::template set_many_empty( blockStartIndex, static_cast(endIndex - blockStartIndex))) { { -#if MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX debug::DebugLock lock(mutex); #endif // Note that the set_many_empty above did a release, meaning that anybody who acquires the block @@ -2945,7 +2952,7 @@ class ConcurrentQueue { } inline size_t get_block_index_index_for_index(index_t index, BlockIndexHeader*& localBlockIndex) const { -#if MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX debug::DebugLock lock(mutex); #endif index &= ~static_cast(BLOCK_SIZE - 1); @@ -3026,10 +3033,10 @@ class ConcurrentQueue { private: #endif -#if MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX mutable debug::DebugMutex mutex; #endif -#if MCDBGQ_TRACKMEM +#ifdef MCDBGQ_TRACKMEM friend struct MemStats; #endif }; @@ -3065,7 +3072,7 @@ class ConcurrentQueue { } inline void add_block_to_free_list(Block* block) { -#if MCDBGQ_TRACKMEM +#ifdef MCDBGQ_TRACKMEM block->owner = nullptr; #endif freeList.add(block); @@ -3103,7 +3110,7 @@ class ConcurrentQueue { return nullptr; } -#if MCDBGQ_TRACKMEM +#ifdef MCDBGQ_TRACKMEM public: struct MemStats { size_t allocatedBlocks; @@ -3221,7 +3228,7 @@ class ConcurrentQueue { } ProducerBase* recycle_or_create_producer(bool isExplicit, bool& recycled) { -#if MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH debug::DebugLock lock(implicitProdMutex); #endif // Try to re-use one first @@ -3386,7 +3393,7 @@ class ConcurrentQueue { // Code and algorithm adapted from http://preshing.com/20130605/the-worlds-simplest-lock-free-hash-table -#if MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH debug::DebugLock lock(implicitProdMutex); #endif @@ -3443,6 +3450,7 @@ class ConcurrentQueue { // Insert! auto newCount = 1 + implicitProducerHashCount.fetch_add(1, std::memory_order_relaxed); while (true) { + // NOLINTNEXTLINE(clang-analyzer-core.NullDereference) if (newCount >= (mainHash->capacity >> 1) && !implicitProducerHashResizeInProgress.test_and_set(std::memory_order_acquire)) { // We've acquired the resize lock, try to allocate a bigger hash table. @@ -3538,8 +3546,8 @@ class ConcurrentQueue { // Remove from thread exit listeners details::ThreadExitNotifier::unsubscribe(&producer->threadExitListener); -// Remove from hash -#if MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH + // Remove from hash +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH debug::DebugLock lock(implicitProdMutex); #endif auto hash = implicitProducerHash.load(std::memory_order_acquire); @@ -3650,7 +3658,7 @@ class ConcurrentQueue { std::atomic nextExplicitConsumerId; std::atomic globalExplicitConsumerOffset; -#if MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH debug::DebugMutex implicitProdMutex; #endif diff --git a/submodules/ton/tonlib-src/tdactor/td/actor/core/ActorInfo.h b/submodules/ton/tonlib-src/tdactor/td/actor/core/ActorInfo.h index e2574c0dbf..974192938a 100644 --- a/submodules/ton/tonlib-src/tdactor/td/actor/core/ActorInfo.h +++ b/submodules/ton/tonlib-src/tdactor/td/actor/core/ActorInfo.h @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once @@ -41,6 +41,7 @@ class ActorInfo : private HeapNode, private ListNode { } ~ActorInfo() { VLOG(actor) << "Destroy actor [" << name_ << "]"; + CHECK(!actor_); } bool is_alive() const { diff --git a/submodules/ton/tonlib-src/tdactor/td/actor/core/CpuWorker.cpp b/submodules/ton/tonlib-src/tdactor/td/actor/core/CpuWorker.cpp index e047eab12a..d752560ddc 100644 --- a/submodules/ton/tonlib-src/tdactor/td/actor/core/CpuWorker.cpp +++ b/submodules/ton/tonlib-src/tdactor/td/actor/core/CpuWorker.cpp @@ -14,13 +14,15 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "td/actor/core/CpuWorker.h" #include "td/actor/core/ActorExecutor.h" #include "td/actor/core/SchedulerContext.h" +#include "td/actor/core/Scheduler.h" // FIXME: afer LocalQueue is in a separate file + namespace td { namespace actor { namespace core { @@ -28,20 +30,64 @@ void CpuWorker::run() { auto thread_id = get_thread_id(); auto &dispatcher = *SchedulerContext::get(); - int yields = 0; + MpmcWaiter::Slot slot; + waiter_.init_slot(slot, thread_id); while (true) { SchedulerMessage message; - if (queue_.try_pop(message, thread_id)) { + if (try_pop(message, thread_id)) { + waiter_.stop_wait(slot); if (!message) { return; } ActorExecutor executor(*message, dispatcher, ActorExecutor::Options().with_from_queue()); - yields = waiter_.stop_wait(yields, thread_id); } else { - yields = waiter_.wait(yields, thread_id); + waiter_.wait(slot); } } } + +bool CpuWorker::try_pop_local(SchedulerMessage &message) { + SchedulerMessage::Raw *raw_message; + if (local_queues_[id_].try_pop(raw_message)) { + message = SchedulerMessage(SchedulerMessage::acquire_t{}, raw_message); + return true; + } + return false; +} + +bool CpuWorker::try_pop_global(SchedulerMessage &message, size_t thread_id) { + SchedulerMessage::Raw *raw_message; + if (queue_.try_pop(raw_message, thread_id)) { + message = SchedulerMessage(SchedulerMessage::acquire_t{}, raw_message); + return true; + } + return false; +} + +bool CpuWorker::try_pop(SchedulerMessage &message, size_t thread_id) { + if (++cnt_ == 51) { + cnt_ = 0; + if (try_pop_global(message, thread_id) || try_pop_local(message)) { + return true; + } + } else { + if (try_pop_local(message) || try_pop_global(message, thread_id)) { + return true; + } + } + + for (size_t i = 1; i < local_queues_.size(); i++) { + size_t pos = (i + id_) % local_queues_.size(); + SchedulerMessage::Raw *raw_message; + if (local_queues_[id_].steal(raw_message, local_queues_[pos])) { + message = SchedulerMessage(SchedulerMessage::acquire_t{}, raw_message); + return true; + } + } + + return false; +} + } // namespace core } // namespace actor } // namespace td diff --git a/submodules/ton/tonlib-src/tdactor/td/actor/core/CpuWorker.h b/submodules/ton/tonlib-src/tdactor/td/actor/core/CpuWorker.h index 63cb337b4d..d9f32513b7 100644 --- a/submodules/ton/tonlib-src/tdactor/td/actor/core/CpuWorker.h +++ b/submodules/ton/tonlib-src/tdactor/td/actor/core/CpuWorker.h @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once @@ -22,19 +22,32 @@ #include "td/utils/MpmcQueue.h" #include "td/utils/MpmcWaiter.h" +#include "td/utils/Span.h" namespace td { namespace actor { namespace core { +template +struct LocalQueue; class CpuWorker { public: - CpuWorker(MpmcQueue &queue, MpmcWaiter &waiter) : queue_(queue), waiter_(waiter) { + CpuWorker(MpmcQueue &queue, MpmcWaiter &waiter, size_t id, + MutableSpan> local_queues) + : queue_(queue), waiter_(waiter), id_(id), local_queues_(local_queues) { } void run(); private: - MpmcQueue &queue_; + MpmcQueue &queue_; MpmcWaiter &waiter_; + size_t id_; + MutableSpan> local_queues_; + size_t cnt_{0}; + + bool try_pop(SchedulerMessage &message, size_t thread_id); + + bool try_pop_local(SchedulerMessage &message); + bool try_pop_global(SchedulerMessage &message, size_t thread_id); }; } // namespace core } // namespace actor diff --git a/submodules/ton/tonlib-src/tdactor/td/actor/core/Scheduler.cpp b/submodules/ton/tonlib-src/tdactor/td/actor/core/Scheduler.cpp index 9569fac360..0863bda0d1 100644 --- a/submodules/ton/tonlib-src/tdactor/td/actor/core/Scheduler.cpp +++ b/submodules/ton/tonlib-src/tdactor/td/actor/core/Scheduler.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "td/actor/core/Scheduler.h" @@ -24,6 +24,7 @@ namespace td { namespace actor { namespace core { + Scheduler::Scheduler(std::shared_ptr scheduler_group_info, SchedulerId id, size_t cpu_threads_count) : scheduler_group_info_(std::move(scheduler_group_info)), cpu_threads_(cpu_threads_count) { scheduler_group_info_->active_scheduler_count++; @@ -31,17 +32,21 @@ Scheduler::Scheduler(std::shared_ptr scheduler_group_info, S info_->id = id; if (cpu_threads_count != 0) { info_->cpu_threads_count = cpu_threads_count; - info_->cpu_queue = std::make_unique>(1024, max_thread_count()); + info_->cpu_queue = std::make_unique>(1024, max_thread_count()); info_->cpu_queue_waiter = std::make_unique(); + + info_->cpu_local_queue = std::vector>(cpu_threads_count); } info_->io_queue = std::make_unique>(); info_->io_queue->init(); info_->cpu_workers.resize(cpu_threads_count); + td::uint8 cpu_worker_id = 0; for (auto &worker : info_->cpu_workers) { - worker = std::make_unique(WorkerInfo::Type::Cpu, true); + worker = std::make_unique(WorkerInfo::Type::Cpu, true, CpuWorkerId{cpu_worker_id}); + cpu_worker_id++; } - info_->io_worker = std::make_unique(WorkerInfo::Type::Io, !info_->cpu_workers.empty()); + info_->io_worker = std::make_unique(WorkerInfo::Type::Io, !info_->cpu_workers.empty(), CpuWorkerId{}); poll_.init(); io_worker_ = std::make_unique(*info_->io_queue); @@ -62,8 +67,9 @@ Scheduler::~Scheduler() { void Scheduler::start() { for (size_t i = 0; i < cpu_threads_.size(); i++) { cpu_threads_[i] = td::thread([this, i] { - this->run_in_context_impl(*this->info_->cpu_workers[i], - [this] { CpuWorker(*info_->cpu_queue, *info_->cpu_queue_waiter).run(); }); + this->run_in_context_impl(*this->info_->cpu_workers[i], [this, i] { + CpuWorker(*info_->cpu_queue, *info_->cpu_queue_waiter, i, info_->cpu_local_queue).run(); + }); }); cpu_threads_[i].set_name(PSLICE() << "#" << info_->id.value() << ":cpu#" << i); } @@ -121,9 +127,14 @@ void Scheduler::do_stop() { scheduler_group_info_->active_scheduler_count_condition_variable.notify_all(); } -Scheduler::ContextImpl::ContextImpl(ActorInfoCreator *creator, SchedulerId scheduler_id, +Scheduler::ContextImpl::ContextImpl(ActorInfoCreator *creator, SchedulerId scheduler_id, CpuWorkerId cpu_worker_id, SchedulerGroupInfo *scheduler_group, Poll *poll, KHeap *heap) - : creator_(creator), scheduler_id_(scheduler_id), scheduler_group_(scheduler_group), poll_(poll), heap_(heap) { + : creator_(creator) + , scheduler_id_(scheduler_id) + , cpu_worker_id_(cpu_worker_id) + , scheduler_group_(scheduler_group) + , poll_(poll) + , heap_(heap) { } SchedulerId Scheduler::ContextImpl::get_scheduler_id() const { @@ -138,7 +149,18 @@ void Scheduler::ContextImpl::add_to_queue(ActorInfoPtr actor_info_ptr, Scheduler if (need_poll || !info.cpu_queue) { info.io_queue->writer_put(std::move(actor_info_ptr)); } else { - info.cpu_queue->push(std::move(actor_info_ptr), get_thread_id()); + if (scheduler_id == get_scheduler_id() && cpu_worker_id_.is_valid()) { + // may push local + CHECK(actor_info_ptr); + auto raw = actor_info_ptr.release(); + auto should_notify = info.cpu_local_queue[cpu_worker_id_.value()].push( + raw, [&](auto value) { info.cpu_queue->push(value, get_thread_id()); }); + if (should_notify) { + info.cpu_queue_waiter->notify(); + } + return; + } + info.cpu_queue->push(actor_info_ptr.release(), get_thread_id()); info.cpu_queue_waiter->notify(); } } @@ -254,13 +276,26 @@ void Scheduler::close_scheduler_group(SchedulerGroupInfo &group_info) { } // Drain cpu queue + for (auto &q : scheduler_info.cpu_local_queue) { + auto &cpu_queue = q; + while (true) { + SchedulerMessage::Raw *raw_message; + if (!cpu_queue.try_pop(raw_message)) { + break; + } + SchedulerMessage(SchedulerMessage::acquire_t{}, raw_message); + // message's destructor is called + queues_are_empty = false; + } + } if (scheduler_info.cpu_queue) { auto &cpu_queue = *scheduler_info.cpu_queue; while (true) { - SchedulerMessage message; - if (!cpu_queue.try_pop(message, get_thread_id())) { + SchedulerMessage::Raw *raw_message; + if (!cpu_queue.try_pop(raw_message, get_thread_id())) { break; } + SchedulerMessage(SchedulerMessage::acquire_t{}, raw_message); // message's destructor is called queues_are_empty = false; } diff --git a/submodules/ton/tonlib-src/tdactor/td/actor/core/Scheduler.h b/submodules/ton/tonlib-src/tdactor/td/actor/core/Scheduler.h index 4ebfc91245..3cc627ee45 100644 --- a/submodules/ton/tonlib-src/tdactor/td/actor/core/Scheduler.h +++ b/submodules/ton/tonlib-src/tdactor/td/actor/core/Scheduler.h @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once @@ -38,9 +38,11 @@ #include "td/utils/List.h" #include "td/utils/logging.h" #include "td/utils/MpmcQueue.h" +#include "td/utils/StealingQueue.h" #include "td/utils/MpmcWaiter.h" #include "td/utils/MpscLinkQueue.h" #include "td/utils/MpscPollableQueue.h" +#include "td/utils/optional.h" #include "td/utils/port/Poll.h" #include "td/utils/port/detail/Iocp.h" #include "td/utils/port/thread.h" @@ -66,16 +68,52 @@ class IoWorker; struct WorkerInfo { enum class Type { Io, Cpu } type{Type::Io}; WorkerInfo() = default; - explicit WorkerInfo(Type type, bool allow_shared) : type(type), actor_info_creator(allow_shared) { + explicit WorkerInfo(Type type, bool allow_shared, CpuWorkerId cpu_worker_id) + : type(type), actor_info_creator(allow_shared), cpu_worker_id(cpu_worker_id) { } ActorInfoCreator actor_info_creator; + CpuWorkerId cpu_worker_id; +}; + +template +struct LocalQueue { + public: + template + bool push(T value, F &&overflow_f) { + auto res = std::move(next_); + next_ = std::move(value); + if (res) { + queue_.local_push(res.unwrap(), overflow_f); + return true; + } + return false; + } + bool try_pop(T &message) { + if (!next_) { + return queue_.local_pop(message); + } + message = next_.unwrap(); + return true; + } + bool steal(T &message, LocalQueue &other) { + return queue_.steal(message, other.queue_); + } + + private: + td::optional next_; + StealingQueue queue_; + char pad[TD_CONCURRENCY_PAD - sizeof(optional)]; }; struct SchedulerInfo { SchedulerId id; // will be read by all workers is any thread - std::unique_ptr> cpu_queue; + std::unique_ptr> cpu_queue; std::unique_ptr cpu_queue_waiter; + + std::vector> cpu_local_queue; + //std::vector> cpu_stealing_queue; + // only scheduler itself may read from io_queue_ std::unique_ptr> io_queue; size_t cpu_threads_count{0}; @@ -156,11 +194,12 @@ class Scheduler { class ContextImpl : public SchedulerContext { public: - ContextImpl(ActorInfoCreator *creator, SchedulerId scheduler_id, SchedulerGroupInfo *scheduler_group, Poll *poll, - KHeap *heap); + ContextImpl(ActorInfoCreator *creator, SchedulerId scheduler_id, CpuWorkerId cpu_worker_id, + SchedulerGroupInfo *scheduler_group, Poll *poll, KHeap *heap); SchedulerId get_scheduler_id() const override; void add_to_queue(ActorInfoPtr actor_info_ptr, SchedulerId scheduler_id, bool need_poll) override; + ActorInfoCreator &get_actor_info_creator() override; bool has_poll() override; @@ -181,6 +220,7 @@ class Scheduler { ActorInfoCreator *creator_; SchedulerId scheduler_id_; + CpuWorkerId cpu_worker_id_; SchedulerGroupInfo *scheduler_group_; Poll *poll_; @@ -193,8 +233,8 @@ class Scheduler { td::detail::Iocp::Guard iocp_guard(&scheduler_group_info_->iocp); #endif bool is_io_worker = worker_info.type == WorkerInfo::Type::Io; - ContextImpl context(&worker_info.actor_info_creator, info_->id, scheduler_group_info_.get(), - is_io_worker ? &poll_ : nullptr, is_io_worker ? &heap_ : nullptr); + ContextImpl context(&worker_info.actor_info_creator, info_->id, worker_info.cpu_worker_id, + scheduler_group_info_.get(), is_io_worker ? &poll_ : nullptr, is_io_worker ? &heap_ : nullptr); SchedulerContext::Guard guard(&context); f(); } diff --git a/submodules/ton/tonlib-src/tdactor/td/actor/core/SchedulerId.h b/submodules/ton/tonlib-src/tdactor/td/actor/core/SchedulerId.h index 124e409276..289adbd475 100644 --- a/submodules/ton/tonlib-src/tdactor/td/actor/core/SchedulerId.h +++ b/submodules/ton/tonlib-src/tdactor/td/actor/core/SchedulerId.h @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once @@ -26,8 +26,7 @@ namespace actor { namespace core { class SchedulerId { public: - SchedulerId() : id_(-1) { - } + SchedulerId() = default; explicit SchedulerId(uint8 id) : id_(id) { } bool is_valid() const { @@ -42,7 +41,27 @@ class SchedulerId { } private: - int32 id_{0}; + int32 id_{-1}; +}; + +class CpuWorkerId { + public: + CpuWorkerId() = default; + explicit CpuWorkerId(uint8 id) : id_(id) { + } + bool is_valid() const { + return id_ >= 0; + } + uint8 value() const { + CHECK(is_valid()); + return static_cast(id_); + } + bool operator==(CpuWorkerId other) const { + return id_ == other.id_; + } + + private: + int32 id_{-1}; }; } // namespace core } // namespace actor diff --git a/submodules/ton/tonlib-src/tdactor/test/actors_core.cpp b/submodules/ton/tonlib-src/tdactor/test/actors_core.cpp index d426f344b5..1ec9dda249 100644 --- a/submodules/ton/tonlib-src/tdactor/test/actors_core.cpp +++ b/submodules/ton/tonlib-src/tdactor/test/actors_core.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "td/actor/core/ActorLocker.h" #include "td/actor/actor.h" @@ -101,10 +101,10 @@ TEST(Actor2, locker) { kill_signal.add_signal(ActorSignals::Kill); ActorSignals wakeup_signal; - kill_signal.add_signal(ActorSignals::Wakeup); + wakeup_signal.add_signal(ActorSignals::Wakeup); ActorSignals cpu_signal; - kill_signal.add_signal(ActorSignals::Cpu); + cpu_signal.add_signal(ActorSignals::Cpu); { ActorLocker lockerA(&state); @@ -410,7 +410,7 @@ class Master : public Actor { private: uint32 l = 0; - uint32 r = 100000; + uint32 r = 1000; core::ActorInfoPtr worker; void start_up() override { worker = detail::create_actor(ActorOptions().with_name("Master")); @@ -444,8 +444,8 @@ TEST(Actor2, scheduler_simple) { core::Scheduler scheduler{group_info, SchedulerId{0}, 2}; scheduler.start(); scheduler.run_in_context([] { - global_cnt = 10; - for (int i = 0; i < 10; i++) { + global_cnt = 1000; + for (int i = 0; i < global_cnt; i++) { detail::create_actor(ActorOptions().with_name("Master")); } }); @@ -734,7 +734,7 @@ TEST(Actor2, actor_ping_pong) { return; } auto dest = td::Random::fast(0, (int)next_.size() - 1); - if (td::Random::fast(0, 1) == 0 && 0) { + if (td::Random::fast(0, 1) == 0) { send_closure(next_[dest], &PingPong::query, left - 1, std::move(data)); } else { send_closure_later(next_[dest], &PingPong::query, left - 1, std::move(data)); @@ -755,7 +755,7 @@ TEST(Actor2, actor_ping_pong) { std::shared_ptr watcher_; }; - int N = td::Random::fast(2, 10); + int N = td::Random::fast(2, 100); //N = 2; std::vector> actors; for (int i = 0; i < N; i++) { diff --git a/submodules/ton/tonlib-src/tddb/td/db/MemoryKeyValue.h b/submodules/ton/tonlib-src/tddb/td/db/MemoryKeyValue.h index f2c261fe67..f2c047138d 100644 --- a/submodules/ton/tonlib-src/tddb/td/db/MemoryKeyValue.h +++ b/submodules/ton/tonlib-src/tddb/td/db/MemoryKeyValue.h @@ -38,11 +38,7 @@ class MemoryKeyValue : public KeyValue { std::string stats() const override; private: - class Cmp : public std::less<> { - public: - using is_transparent = void; - }; - std::map map_; + std::map> map_; int64 get_count_{0}; }; } // namespace td diff --git a/submodules/ton/tonlib-src/tddb/td/db/RocksDb.cpp b/submodules/ton/tonlib-src/tddb/td/db/RocksDb.cpp index 16f4b4eb80..47fdf4f5c2 100644 --- a/submodules/ton/tonlib-src/tddb/td/db/RocksDb.cpp +++ b/submodules/ton/tonlib-src/tddb/td/db/RocksDb.cpp @@ -19,6 +19,7 @@ #include "td/db/RocksDb.h" #include "rocksdb/db.h" +#include "rocksdb/table.h" #include "rocksdb/statistics.h" #include "rocksdb/write_batch.h" #include "rocksdb/utilities/optimistic_transaction_db.h" @@ -63,6 +64,13 @@ Result RocksDb::open(std::string path) { auto statistics = rocksdb::CreateDBStatistics(); { rocksdb::Options options; + + static auto cache = rocksdb::NewLRUCache(1 << 30); + + rocksdb::BlockBasedTableOptions table_options; + table_options.block_cache = cache; + options.table_factory.reset(rocksdb::NewBlockBasedTableFactory(table_options)); + options.manual_wal_flush = true; options.create_if_missing = true; options.max_background_compactions = 4; @@ -82,6 +90,10 @@ std::unique_ptr RocksDb::snapshot() { } std::string RocksDb::stats() const { + std::string out; + db_->GetProperty("rocksdb.stats", &out); + //db_->GetProperty("rocksdb.cur-size-all-mem-tables", &out); + return out; return statistics_->ToString(); } diff --git a/submodules/ton/tonlib-src/tddb/td/db/RocksDb.h b/submodules/ton/tonlib-src/tddb/td/db/RocksDb.h index 04abba778d..77ed46b34b 100644 --- a/submodules/ton/tonlib-src/tddb/td/db/RocksDb.h +++ b/submodules/ton/tonlib-src/tddb/td/db/RocksDb.h @@ -60,6 +60,10 @@ class RocksDb : public KeyValue { RocksDb &operator=(RocksDb &&); ~RocksDb(); + std::shared_ptr raw_db() const { + return db_; + }; + private: std::shared_ptr db_; std::shared_ptr statistics_; diff --git a/submodules/ton/tonlib-src/tddb/test/binlog.cpp b/submodules/ton/tonlib-src/tddb/test/binlog.cpp index fc46157ca6..d2cd35225f 100644 --- a/submodules/ton/tonlib-src/tddb/test/binlog.cpp +++ b/submodules/ton/tonlib-src/tddb/test/binlog.cpp @@ -679,7 +679,7 @@ TEST(Buffers, CyclicBufferSimple) { auto data = td::rand_string('a', 'z', 100001); td::Slice write_slice = data; td::Slice read_slice = data; - for (size_t i = 1; (int)i < options.count; i++) { + for (size_t i = 1; i < options.count; i++) { ASSERT_EQ((i - 1) * options.chunk_size, reader.reader_size()); ASSERT_EQ((i - 1) * options.chunk_size, writer.writer_size()); auto slice = writer.prepare_write(); diff --git a/submodules/ton/tonlib-src/tddb/test/key_value.cpp b/submodules/ton/tonlib-src/tddb/test/key_value.cpp index 550ccd2fad..cf147e5721 100644 --- a/submodules/ton/tonlib-src/tddb/test/key_value.cpp +++ b/submodules/ton/tonlib-src/tddb/test/key_value.cpp @@ -170,7 +170,11 @@ TEST(KeyValue, Bench) { TEST(KeyValue, Stress) { return; td::Slice db_name = "testdb"; - td::RocksDb::destroy(db_name).ignore(); + size_t N = 20; + auto db_name_i = [&](size_t i) { return PSTRING() << db_name << i; }; + for (size_t i = 0; i < N; i++) { + td::RocksDb::destroy(db_name_i(i)).ignore(); + } td::actor::Scheduler scheduler({6}); auto watcher = td::create_shared_destructor([] { td::actor::SchedulerContext::get()->stop(); }); @@ -186,9 +190,13 @@ TEST(KeyValue, Stress) { void tear_down() override { } void loop() override { + if (stat_at_.is_in_past()) { + stat_at_ = td::Timestamp::in(10); + LOG(ERROR) << db_->stats(); + } if (!kv_) { - kv_ = td::KeyValueAsync( - std::make_unique(td::RocksDb::open(db_name_).move_as_ok())); + db_ = std::make_shared(td::RocksDb::open(db_name_).move_as_ok()); + kv_ = td::KeyValueAsync(db_); set_start_at_ = td::Timestamp::now(); } if (next_set_ && next_set_.is_in_past()) { @@ -207,6 +215,7 @@ TEST(KeyValue, Stress) { private: std::shared_ptr watcher_; + std::shared_ptr db_; td::optional> kv_; std::string db_name_; int left_cnt_ = 1000000000; @@ -214,6 +223,7 @@ TEST(KeyValue, Stress) { td::Timestamp next_set_ = td::Timestamp::now(); td::Timestamp set_start_at_; td::Timestamp set_finish_at_; + td::Timestamp stat_at_ = td::Timestamp::in(10); void do_set() { td::UInt128 key = td::UInt128::zero(); @@ -236,8 +246,10 @@ TEST(KeyValue, Stress) { } } }; - scheduler.run_in_context([watcher = std::move(watcher), &db_name]() mutable { - td::actor::create_actor("Worker", watcher, db_name.str()).release(); + scheduler.run_in_context([watcher = std::move(watcher), &db_name_i, &N]() mutable { + for (size_t i = 0; i < N; i++) { + td::actor::create_actor("Worker", watcher, db_name_i(i)).release(); + } watcher.reset(); }); diff --git a/submodules/ton/tonlib-src/tdutils/CMakeLists.txt b/submodules/ton/tonlib-src/tdutils/CMakeLists.txt index ed82dbb12f..721a32b7d1 100644 --- a/submodules/ton/tonlib-src/tdutils/CMakeLists.txt +++ b/submodules/ton/tonlib-src/tdutils/CMakeLists.txt @@ -56,6 +56,7 @@ set(TDUTILS_SOURCE td/utils/port/MemoryMapping.cpp td/utils/port/path.cpp td/utils/port/PollFlags.cpp + td/utils/port/rlimit.cpp td/utils/port/ServerSocketFd.cpp td/utils/port/signals.cpp td/utils/port/sleep.cpp @@ -129,6 +130,7 @@ set(TDUTILS_SOURCE td/utils/port/Poll.h td/utils/port/PollBase.h td/utils/port/PollFlags.h + td/utils/port/rlimit.h td/utils/port/RwMutex.h td/utils/port/ServerSocketFd.h td/utils/port/signals.h @@ -228,6 +230,7 @@ set(TDUTILS_SOURCE td/utils/SpinLock.h td/utils/StackAllocator.h td/utils/Status.h + td/utils/StealingQueue.h td/utils/Storer.h td/utils/StorerBase.h td/utils/StringBuilder.h @@ -279,6 +282,7 @@ set(TDUTILS_TEST_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/test/pq.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test/SharedObjectPool.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test/SharedSlice.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/test/StealingQueue.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test/variant.cpp PARENT_SCOPE ) diff --git a/submodules/ton/tonlib-src/tdutils/td/utils/BufferedFd.h b/submodules/ton/tonlib-src/tdutils/td/utils/BufferedFd.h index 8dff309144..9940eb1e7b 100644 --- a/submodules/ton/tonlib-src/tdutils/td/utils/BufferedFd.h +++ b/submodules/ton/tonlib-src/tdutils/td/utils/BufferedFd.h @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once @@ -84,6 +84,12 @@ class BufferedFd : public BufferedFdBase { ~BufferedFd(); void close(); + size_t left_unread() { + return input_reader_.size(); + } + size_t left_unwritten() { + return output_reader_.size(); + } Result flush_read(size_t max_read = std::numeric_limits::max()) TD_WARN_UNUSED_RESULT; Result flush_write() TD_WARN_UNUSED_RESULT; diff --git a/submodules/ton/tonlib-src/tdutils/td/utils/FileLog.cpp b/submodules/ton/tonlib-src/tdutils/td/utils/FileLog.cpp index 49a0a6276d..7f36deed83 100644 --- a/submodules/ton/tonlib-src/tdutils/td/utils/FileLog.cpp +++ b/submodules/ton/tonlib-src/tdutils/td/utils/FileLog.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "td/utils/FileLog.h" @@ -128,4 +128,10 @@ void FileLog::do_rotate() { SET_VERBOSITY_LEVEL(current_verbosity_level); } +Result> FileLog::create(string path, int64 rotate_threshold, bool redirect_stderr) { + auto l = make_unique(); + TRY_STATUS(l->init(std::move(path), rotate_threshold, redirect_stderr)); + return std::move(l); +} + } // namespace td diff --git a/submodules/ton/tonlib-src/tdutils/td/utils/FileLog.h b/submodules/ton/tonlib-src/tdutils/td/utils/FileLog.h index 63708c16aa..2cead1be5a 100644 --- a/submodules/ton/tonlib-src/tdutils/td/utils/FileLog.h +++ b/submodules/ton/tonlib-src/tdutils/td/utils/FileLog.h @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once @@ -30,6 +30,8 @@ class FileLog : public LogInterface { static constexpr int64 DEFAULT_ROTATE_THRESHOLD = 10 * (1 << 20); public: + static Result> create(string path, int64 rotate_threshold = DEFAULT_ROTATE_THRESHOLD, + bool redirect_stderr = true); Status init(string path, int64 rotate_threshold = DEFAULT_ROTATE_THRESHOLD, bool redirect_stderr = true); Slice get_path() const; diff --git a/submodules/ton/tonlib-src/tdutils/td/utils/MpmcQueue.h b/submodules/ton/tonlib-src/tdutils/td/utils/MpmcQueue.h index 2daf61472b..e6504e358c 100644 --- a/submodules/ton/tonlib-src/tdutils/td/utils/MpmcQueue.h +++ b/submodules/ton/tonlib-src/tdutils/td/utils/MpmcQueue.h @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once @@ -117,24 +117,28 @@ template class OneValue { public: bool set_value(T *value) { - T *was = nullptr; + T *was = Empty(); return state_.compare_exchange_strong(was, value, std::memory_order_acq_rel); } bool get_value(T *&value) { value = state_.exchange(Taken(), std::memory_order_acq_rel); - return value != nullptr; + return value != Empty(); } void reset() { - state_ = nullptr; + state_ = Empty(); } OneValue() { } private: - std::atomic state_{nullptr}; - T *Taken() { - static T xxx; - return &xxx; + std::atomic state_{Empty()}; + static T *Empty() { + static int64 xxx; + return reinterpret_cast(&xxx); + } + static T *Taken() { + static int64 xxx; + return reinterpret_cast(&xxx); } }; diff --git a/submodules/ton/tonlib-src/tdutils/td/utils/MpmcWaiter.h b/submodules/ton/tonlib-src/tdutils/td/utils/MpmcWaiter.h index 42864cae56..8fb1a5111e 100644 --- a/submodules/ton/tonlib-src/tdutils/td/utils/MpmcWaiter.h +++ b/submodules/ton/tonlib-src/tdutils/td/utils/MpmcWaiter.h @@ -14,63 +14,86 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once #include "td/utils/common.h" +#include "td/utils/logging.h" #include "td/utils/port/thread.h" #include +#include #include #include namespace td { -class MpmcWaiter { +class MpmcEagerWaiter { public: - int wait(int yields, uint32 worker_id) { - if (yields < RoundsTillSleepy) { + struct Slot { + private: + friend class MpmcEagerWaiter; + int yields; + uint32 worker_id; + }; + void init_slot(Slot &slot, uint32 worker_id) { + slot.yields = 0; + slot.worker_id = worker_id; + } + void wait(Slot &slot) { + if (slot.yields < RoundsTillSleepy) { td::this_thread::yield(); - return yields + 1; - } else if (yields == RoundsTillSleepy) { + slot.yields++; + return; + } else if (slot.yields == RoundsTillSleepy) { auto state = state_.load(std::memory_order_relaxed); if (!State::has_worker(state)) { - auto new_state = State::with_worker(state, worker_id); + auto new_state = State::with_worker(state, slot.worker_id); if (state_.compare_exchange_strong(state, new_state, std::memory_order_acq_rel)) { td::this_thread::yield(); - return yields + 1; + slot.yields++; + return; } if (state == State::awake()) { - return 0; + slot.yields = 0; + return; } } td::this_thread::yield(); - return 0; - } else if (yields < RoundsTillAsleep) { + slot.yields = 0; + return; + } else if (slot.yields < RoundsTillAsleep) { auto state = state_.load(std::memory_order_acquire); - if (State::still_sleepy(state, worker_id)) { + if (State::still_sleepy(state, slot.worker_id)) { td::this_thread::yield(); - return yields + 1; + slot.yields++; + return; } - return 0; + slot.yields = 0; + return; } else { auto state = state_.load(std::memory_order_acquire); - if (State::still_sleepy(state, worker_id)) { + if (State::still_sleepy(state, slot.worker_id)) { std::unique_lock lock(mutex_); if (state_.compare_exchange_strong(state, State::asleep(), std::memory_order_acq_rel)) { condition_variable_.wait(lock); } } - return 0; + slot.yields = 0; + return; } } - int stop_wait(int yields, uint32 worker_id) { - if (yields > RoundsTillSleepy) { + void stop_wait(Slot &slot) { + if (slot.yields > RoundsTillSleepy) { notify_cold(); } - return 0; + slot.yields = 0; + return; + } + + void close() { } void notify() { @@ -102,8 +125,8 @@ class MpmcWaiter { return (state >> 1) == (worker + 1); } }; - //enum { RoundsTillSleepy = 32, RoundsTillAsleep = 64 }; - enum { RoundsTillSleepy = 1, RoundsTillAsleep = 2 }; + enum { RoundsTillSleepy = 32, RoundsTillAsleep = 64 }; + // enum { RoundsTillSleepy = 1, RoundsTillAsleep = 2 }; std::atomic state_{State::awake()}; std::mutex mutex_; std::condition_variable condition_variable_; @@ -117,4 +140,208 @@ class MpmcWaiter { } }; +class MpmcSleepyWaiter { + public: + struct Slot { + private: + friend class MpmcSleepyWaiter; + + enum State { Search, Work, Sleep } state_{Work}; + + void park() { + std::unique_lock guard(mutex_); + condition_variable_.wait(guard, [&] { return unpark_flag_; }); + unpark_flag_ = false; + } + + bool cancel_park() { + auto res = unpark_flag_; + unpark_flag_ = false; + return res; + } + + void unpark() { + //TODO: try unlock guard before notify_all + std::unique_lock guard(mutex_); + unpark_flag_ = true; + condition_variable_.notify_all(); + } + + std::mutex mutex_; + std::condition_variable condition_variable_; + bool unpark_flag_{false}; // TODO: move out of lock + int yield_cnt{0}; + int32 worker_id{0}; + char padding[128]; + }; + + // There are a lot of workers + // Each has a slot + // + // States of a worker: + // - searching for work | Search + // - processing work | Work + // - sleeping | Sleep + // + // When somebody adds a work it calls notify + // + // notify + // if there are workers in search phase do nothing. + // if all workers are awake do nothing + // otherwise wake some random worker + // + // Initially all workers are in Search mode. + // + // When worker found nothing it may try to call wait. + // This may put it in a Sleep for some time. + // After wait return worker will be in Search state again. + // + // Suppose worker found a work and ready to process it. + // Than it may call stop_wait. This will cause transition from + // Search to Work state. + // + // Main invariant: + // After notify is called there should be at least on worker in Search or Work state. + // If possible - in Search state + // + + void init_slot(Slot &slot, int32 worker_id) { + slot.state_ = Slot::State::Work; + slot.unpark_flag_ = false; + slot.worker_id = worker_id; + VLOG(waiter) << "Init slot " << worker_id; + } + + int VERBOSITY_NAME(waiter) = VERBOSITY_NAME(DEBUG) + 10; + void wait(Slot &slot) { + if (slot.state_ == Slot::State::Work) { + VLOG(waiter) << "Work -> Search"; + state_++; + slot.state_ = Slot::State::Search; + slot.yield_cnt = 0; + return; + } + if (slot.state_ == Slot::Search) { + if (slot.yield_cnt++ < 10 && false) { + td::this_thread::yield(); + return; + } + + slot.state_ = Slot::State::Sleep; + std::unique_lock guard(sleepers_mutex_); + auto state_view = StateView(state_.fetch_add((1 << PARKING_SHIFT) - 1)); + CHECK(state_view.searching_count != 0); + bool should_search = state_view.searching_count == 1; + if (closed_) { + return; + } + sleepers_.push_back(&slot); + LOG_CHECK(slot.unpark_flag_ == false) << slot.worker_id; + VLOG(waiter) << "add to sleepers " << slot.worker_id; + //guard.unlock(); + if (should_search) { + VLOG(waiter) << "Search -> Search once then Sleep "; + return; + } + VLOG(waiter) << "Search -> Sleep " << state_view.searching_count << " " << state_view.parked_count; + } + + CHECK(slot.state_ == Slot::State::Sleep); + VLOG(waiter) << "Park " << slot.worker_id; + slot.park(); + VLOG(waiter) << "Resume " << slot.worker_id; + slot.state_ = Slot::State::Search; + slot.yield_cnt = 0; + } + + void stop_wait(Slot &slot) { + if (slot.state_ == Slot::State::Work) { + return; + } + if (slot.state_ == Slot::State::Sleep) { + VLOG(waiter) << "Search once then Sleep -> Work/Search " << slot.worker_id; + slot.state_ = Slot::State::Work; + std::unique_lock guard(sleepers_mutex_); + auto it = std::find(sleepers_.begin(), sleepers_.end(), &slot); + if (it != sleepers_.end()) { + sleepers_.erase(it); + VLOG(waiter) << "remove from sleepers " << slot.worker_id; + state_.fetch_sub((1 << PARKING_SHIFT) - 1); + guard.unlock(); + } else { + guard.unlock(); + VLOG(waiter) << "not in sleepers" << slot.worker_id; + CHECK(slot.cancel_park()); + } + } + VLOG(waiter) << "Search once then Sleep -> Work " << slot.worker_id; + slot.state_ = Slot::State::Search; + auto state_view = StateView(state_.fetch_sub(1)); + CHECK(state_view.searching_count != 0); + CHECK(state_view.searching_count < 1000); + bool should_notify = state_view.searching_count == 1; + if (should_notify) { + VLOG(waiter) << "Notify others"; + notify(); + } + VLOG(waiter) << "Search -> Work "; + slot.state_ = Slot::State::Work; + } + + void notify() { + auto view = StateView(state_.load()); + //LOG(ERROR) << view.parked_count; + if (view.searching_count > 0 || view.parked_count == 0) { + VLOG(waiter) << "Ingore notify: " << view.searching_count << " " << view.parked_count; + return; + } + + VLOG(waiter) << "Notify: " << view.searching_count << " " << view.parked_count; + std::unique_lock guard(sleepers_mutex_); + + view = StateView(state_.load()); + if (view.searching_count > 0) { + VLOG(waiter) << "Skip notify: got searching"; + return; + } + + CHECK(view.parked_count == static_cast(sleepers_.size())); + if (sleepers_.empty()) { + VLOG(waiter) << "Skip notify: no sleepers"; + return; + } + + auto sleeper = sleepers_.back(); + sleepers_.pop_back(); + state_.fetch_sub((1 << PARKING_SHIFT) - 1); + VLOG(waiter) << "Unpark " << sleeper->worker_id; + sleeper->unpark(); + } + + void close() { + StateView state(state_.load()); + LOG_CHECK(state.parked_count == 0) << state.parked_count; + LOG_CHECK(state.searching_count == 0) << state.searching_count; + } + + private: + static constexpr td::int32 PARKING_SHIFT = 16; + struct StateView { + td::int32 parked_count; + td::int32 searching_count; + explicit StateView(int32 x) { + parked_count = x >> PARKING_SHIFT; + searching_count = x & ((1 << PARKING_SHIFT) - 1); + } + }; + std::atomic state_{0}; + + std::mutex sleepers_mutex_; + std::vector sleepers_; + + bool closed_ = false; +}; + +using MpmcWaiter = MpmcSleepyWaiter; + } // namespace td diff --git a/submodules/ton/tonlib-src/tdutils/td/utils/SharedObjectPool.h b/submodules/ton/tonlib-src/tdutils/td/utils/SharedObjectPool.h index 5f60614246..0a9123d317 100644 --- a/submodules/ton/tonlib-src/tdutils/td/utils/SharedObjectPool.h +++ b/submodules/ton/tonlib-src/tdutils/td/utils/SharedObjectPool.h @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once @@ -49,9 +49,7 @@ class AtomicRefCnt { }; template -class SharedPtrRaw - : public DeleterT - , private MpscLinkQueueImpl::Node { +class SharedPtrRaw : public DeleterT, private MpscLinkQueueImpl::Node { public: explicit SharedPtrRaw(DeleterT deleter) : DeleterT(std::move(deleter)), ref_cnt_{0}, option_magic_(Magic) { } @@ -100,6 +98,7 @@ template > class SharedPtr { public: using Raw = detail::SharedPtrRaw; + struct acquire_t {}; SharedPtr() = default; ~SharedPtr() { if (!raw_) { @@ -112,6 +111,8 @@ class SharedPtr { raw_->inc(); } } + SharedPtr(acquire_t, Raw *raw) : raw_(raw) { + } SharedPtr(const SharedPtr &other) : SharedPtr(other.raw_) { } SharedPtr &operator=(const SharedPtr &other) { diff --git a/submodules/ton/tonlib-src/tdutils/td/utils/Span.h b/submodules/ton/tonlib-src/tdutils/td/utils/Span.h index 8c8ee110b5..a4a8edffa3 100644 --- a/submodules/ton/tonlib-src/tdutils/td/utils/Span.h +++ b/submodules/ton/tonlib-src/tdutils/td/utils/Span.h @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once @@ -95,6 +95,12 @@ class SpanImpl { InnerT *end() const { return data_ + size_; } + auto rbegin() const { + return std::reverse_iterator(end()); + } + auto rend() const { + return std::reverse_iterator(begin()); + } size_t size() const { return size_; } diff --git a/submodules/ton/tonlib-src/tdutils/td/utils/Status.h b/submodules/ton/tonlib-src/tdutils/td/utils/Status.h index 6ac9210059..8016099fa7 100644 --- a/submodules/ton/tonlib-src/tdutils/td/utils/Status.h +++ b/submodules/ton/tonlib-src/tdutils/td/utils/Status.h @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once @@ -64,6 +64,9 @@ #define TRY_RESULT_ASSIGN(name, result) TRY_RESULT_IMPL(TD_CONCAT(TD_CONCAT(r_, name), __LINE__), name, result) +#define TRY_RESULT_PROMISE_ASSIGN(promise_name, name, result) \ + TRY_RESULT_PROMISE_IMPL(promise_name, TD_CONCAT(TD_CONCAT(r_, name), __LINE__), name, result) + #define TRY_RESULT_PREFIX(name, result, prefix) \ TRY_RESULT_PREFIX_IMPL(TD_CONCAT(TD_CONCAT(r_, name), __LINE__), auto name, result, prefix) diff --git a/submodules/ton/tonlib-src/tdutils/td/utils/StealingQueue.h b/submodules/ton/tonlib-src/tdutils/td/utils/StealingQueue.h new file mode 100644 index 0000000000..20a39dc060 --- /dev/null +++ b/submodules/ton/tonlib-src/tdutils/td/utils/StealingQueue.h @@ -0,0 +1,124 @@ +/* + This file is part of TON Blockchain Library. + + TON Blockchain Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + TON Blockchain Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with TON Blockchain Library. If not, see . + + Copyright 2019-2020 Telegram Systems LLP +*/ +#pragma once + +#include "td/utils/Status.h" +#include "td/utils/Span.h" +namespace td { +template +class StealingQueue { + public: + // tries to put a value + // returns if succeeded + // only owner is alowed to to do this + template + void local_push(T value, F&& overflow_f) { + while (true) { + auto tail = tail_.load(std::memory_order_relaxed); + auto head = head_.load(); //TODO: memory order + + if (static_cast(tail - head) < N) { + buf_[tail & MASK].store(value, std::memory_order_relaxed); + tail_.store(tail + 1, std::memory_order_release); + return; + } + + // queue is full + // TODO: batch insert into global queue? + auto n = N / 2 + 1; + auto new_head = head + n; + if (!head_.compare_exchange_strong(head, new_head)) { + continue; + } + + for (size_t i = 0; i < n; i++) { + overflow_f(buf_[(i + head) & MASK].load(std::memory_order_relaxed)); + } + overflow_f(value); + + return; + } + } + + // tries to pop a value + // returns if succeeded + // only owner is alowed to to do this + bool local_pop(T& value) { + auto tail = tail_.load(std::memory_order_relaxed); + auto head = head_.load(); + + if (head == tail) { + return false; + } + + value = buf_[head & MASK].load(std::memory_order_relaxed); + return head_.compare_exchange_strong(head, head + 1); + } + + bool steal(T& value, StealingQueue& other) { + while (true) { + auto tail = tail_.load(std::memory_order_relaxed); + auto head = head_.load(); //TODO: memory order + + auto other_head = other.head_.load(); + auto other_tail = other.tail_.load(std::memory_order_acquire); + + if (other_tail < other_head) { + continue; + } + size_t n = other_tail - other_head; + if (n > N) { + continue; + } + n -= n / 2; + n = td::min(n, static_cast(head + N - tail)); + if (n == 0) { + return false; + } + + for (size_t i = 0; i < n; i++) { + buf_[(i + tail) & MASK].store(other.buf_[(i + other_head) & MASK].load(std::memory_order_relaxed), + std::memory_order_relaxed); + } + + if (!other.head_.compare_exchange_strong(other_head, other_head + n)) { + continue; + } + + n--; + value = buf_[(tail + n) & MASK].load(std::memory_order_relaxed); + tail_.store(tail + n, std::memory_order_release); + return true; + } + } + + StealingQueue() { + for (auto& x : buf_) { + x.store(T{}, std::memory_order_relaxed); + } + std::atomic_thread_fence(std::memory_order_seq_cst); + } + + private: + std::atomic head_{0}; + std::atomic tail_{0}; + static constexpr size_t MASK{N - 1}; + std::array, N> buf_; +}; +}; // namespace td diff --git a/submodules/ton/tonlib-src/tdutils/td/utils/StringBuilder.h b/submodules/ton/tonlib-src/tdutils/td/utils/StringBuilder.h index 229b967e80..5fe1e94219 100644 --- a/submodules/ton/tonlib-src/tdutils/td/utils/StringBuilder.h +++ b/submodules/ton/tonlib-src/tdutils/td/utils/StringBuilder.h @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once diff --git a/submodules/ton/tonlib-src/tdutils/td/utils/TsFileLog.cpp b/submodules/ton/tonlib-src/tdutils/td/utils/TsFileLog.cpp index e36b4fc50d..865faa4b46 100644 --- a/submodules/ton/tonlib-src/tdutils/td/utils/TsFileLog.cpp +++ b/submodules/ton/tonlib-src/tdutils/td/utils/TsFileLog.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "TsFileLog.h" @@ -24,8 +24,10 @@ namespace td { namespace detail { class TsFileLog : public LogInterface { public: - Status init(string path) { + Status init(string path, td::int64 rotate_threshold, bool redirect_stderr) { path_ = std::move(path); + rotate_threshold_ = rotate_threshold; + redirect_stderr_ = redirect_stderr; for (int i = 0; i < (int)logs_.size(); i++) { logs_[i].id = i; } @@ -54,6 +56,8 @@ class TsFileLog : public LogInterface { int id; }; static constexpr int MAX_THREAD_ID = 128; + td::int64 rotate_threshold_; + bool redirect_stderr_; std::string path_; std::array logs_; @@ -70,7 +74,7 @@ class TsFileLog : public LogInterface { } Status init_info(Info *info) { - TRY_STATUS(info->log.init(get_path(info), std::numeric_limits::max(), info->id == 0)); + TRY_STATUS(info->log.init(get_path(info), std::numeric_limits::max(), info->id == 0 && redirect_stderr_)); info->is_inited = true; return Status::OK(); } @@ -92,9 +96,9 @@ class TsFileLog : public LogInterface { }; } // namespace detail -Result> TsFileLog::create(string path) { +Result> TsFileLog::create(string path, td::int64 rotate_threshold, bool redirect_stderr) { auto res = td::make_unique(); - TRY_STATUS(res->init(path)); + TRY_STATUS(res->init(path, rotate_threshold, redirect_stderr)); return std::move(res); } } // namespace td diff --git a/submodules/ton/tonlib-src/tdutils/td/utils/TsFileLog.h b/submodules/ton/tonlib-src/tdutils/td/utils/TsFileLog.h index a34572af51..0ebac8ebff 100644 --- a/submodules/ton/tonlib-src/tdutils/td/utils/TsFileLog.h +++ b/submodules/ton/tonlib-src/tdutils/td/utils/TsFileLog.h @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once @@ -22,7 +22,10 @@ namespace td { class TsFileLog { + static constexpr int64 DEFAULT_ROTATE_THRESHOLD = 10 * (1 << 20); + public: - static Result> create(string path); + static Result> create(string path, int64 rotate_threshold = DEFAULT_ROTATE_THRESHOLD, + bool redirect_stderr = true); }; } // namespace td diff --git a/submodules/ton/tonlib-src/tdutils/td/utils/Variant.h b/submodules/ton/tonlib-src/tdutils/td/utils/Variant.h index 30777a164a..708fc1cb66 100644 --- a/submodules/ton/tonlib-src/tdutils/td/utils/Variant.h +++ b/submodules/ton/tonlib-src/tdutils/td/utils/Variant.h @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once @@ -253,6 +253,10 @@ class Variant { return offset_; } + bool empty() const { + return offset_ == npos; + } + private: union { int64 align_; diff --git a/submodules/ton/tonlib-src/tdutils/td/utils/base64.cpp b/submodules/ton/tonlib-src/tdutils/td/utils/base64.cpp index 67874d2141..356b3af388 100644 --- a/submodules/ton/tonlib-src/tdutils/td/utils/base64.cpp +++ b/submodules/ton/tonlib-src/tdutils/td/utils/base64.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "td/utils/base64.h" @@ -30,6 +30,68 @@ namespace td { //TODO: fix copypaste +static const char *const symbols32_lc = "abcdefghijklmnopqrstuvwxyz234567"; +static const char *const symbols32_uc = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; + +string base32_encode(Slice input, bool upper_case) { + auto *symbols32 = (upper_case ? symbols32_uc : symbols32_lc); + string base32; + base32.reserve((input.size() * 8 + 4) / 5); + uint32 c = 0; + uint32 length = 0; + for (size_t i = 0; i < input.size(); i++) { + c = (c << 8) | input.ubegin()[i]; + length += 8; + while (length >= 5) { + length -= 5; + base32.push_back(symbols32[(c >> length) & 31]); + } + } + if (length != 0) { + base32.push_back(symbols32[(c << (5 - length)) & 31]); + } + //TODO: optional padding + return base32; +} + +static unsigned char b32_char_to_value[256]; +static void init_base32_table() { + static bool is_inited = [] { + std::fill(std::begin(b32_char_to_value), std::end(b32_char_to_value), static_cast(32)); + for (unsigned char i = 0; i < 32; i++) { + b32_char_to_value[static_cast(symbols32_lc[i])] = i; + b32_char_to_value[static_cast(symbols32_uc[i])] = i; + } + return true; + }(); + CHECK(is_inited); +} + +Result base32_decode(Slice base32) { + init_base32_table(); + string res; + res.reserve(base32.size() * 5 / 8); + uint32 c = 0; + uint32 length = 0; + for (size_t i = 0; i < base32.size(); i++) { + auto value = b32_char_to_value[base32.ubegin()[i]]; + if (value == 32) { + return Status::Error("Wrong character in the string"); + } + c = (c << 5) | value; + length += 5; + while (length >= 8) { + length -= 8; + res.push_back(td::uint8((c >> length) & 255)); + } + } + if ((c & ((1 << length) - 1)) != 0) { + return Status::Error("Nonzero padding"); + } + //TODO: check padding + return res; +} + static const char *const symbols64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; string base64_encode(Slice input) { diff --git a/submodules/ton/tonlib-src/tdutils/td/utils/base64.h b/submodules/ton/tonlib-src/tdutils/td/utils/base64.h index f17cf3eb7c..bf46a83541 100644 --- a/submodules/ton/tonlib-src/tdutils/td/utils/base64.h +++ b/submodules/ton/tonlib-src/tdutils/td/utils/base64.h @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once @@ -37,4 +37,7 @@ bool is_base64url(Slice input); string base64_filter(Slice input); +string base32_encode(Slice input, bool upper_case = false); +Result base32_decode(Slice base32); + } // namespace td diff --git a/submodules/ton/tonlib-src/tdutils/td/utils/bits.h b/submodules/ton/tonlib-src/tdutils/td/utils/bits.h index d4ab932e31..1197b9db23 100644 --- a/submodules/ton/tonlib-src/tdutils/td/utils/bits.h +++ b/submodules/ton/tonlib-src/tdutils/td/utils/bits.h @@ -139,7 +139,13 @@ inline uint64 bswap64(uint64 x) { } inline int32 count_bits32(uint32 x) { - return __popcnt(x); + // Do not use __popcnt because it will fail on some platforms. + x -= (x >> 1) & 0x55555555; + x = (x & 0x33333333) + ((x >> 2) & 0x33333333); + x = (x + (x >> 4)) & 0x0F0F0F0F; + x += x >> 8; + return (x + (x >> 16)) & 0x3F; + //return __popcnt(x); } inline int32 count_bits64(uint64 x) { diff --git a/submodules/ton/tonlib-src/tdutils/td/utils/misc.h b/submodules/ton/tonlib-src/tdutils/td/utils/misc.h index d747313eb8..ceba11daae 100644 --- a/submodules/ton/tonlib-src/tdutils/td/utils/misc.h +++ b/submodules/ton/tonlib-src/tdutils/td/utils/misc.h @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once @@ -44,12 +44,12 @@ std::pair split(T s, char delimiter = ' ') { } template -vector full_split(T s, char delimiter = ' ') { +vector full_split(T s, char delimiter = ' ', size_t max_parts = std::numeric_limits::max()) { vector result; if (s.empty()) { return result; } - while (true) { + while (result.size() + 1 < max_parts) { auto delimiter_pos = s.find(delimiter); if (delimiter_pos == string::npos) { result.push_back(std::move(s)); @@ -59,6 +59,8 @@ vector full_split(T s, char delimiter = ' ') { s = s.substr(delimiter_pos + 1); } } + result.push_back(std::move(s)); + return result; } string implode(const vector &v, char delimiter = ' '); @@ -301,6 +303,20 @@ typename std::enable_if::value, T>::type hex_to_integer(Slic return integer_value; } +template +Result::value, T>::type> hex_to_integer_safe(Slice str) { + T integer_value = 0; + auto begin = str.begin(); + auto end = str.end(); + while (begin != end) { + if (!is_hex_digit(*begin)) { + return Status::Error("not a hex digit"); + } + integer_value = static_cast(integer_value * 16 + hex_to_int(*begin++)); + } + return integer_value; +} + double to_double(Slice str); template diff --git a/submodules/ton/tonlib-src/tdutils/td/utils/optional.h b/submodules/ton/tonlib-src/tdutils/td/utils/optional.h index 7da14b6294..3eb2d51822 100644 --- a/submodules/ton/tonlib-src/tdutils/td/utils/optional.h +++ b/submodules/ton/tonlib-src/tdutils/td/utils/optional.h @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once @@ -74,6 +74,13 @@ class optional { return res; } + td::optional copy() const { + if (*this) { + return value(); + } + return {}; + } + template void emplace(ArgsT &&... args) { impl_.emplace(std::forward(args)...); diff --git a/submodules/ton/tonlib-src/tdutils/td/utils/port/detail/Epoll.cpp b/submodules/ton/tonlib-src/tdutils/td/utils/port/detail/Epoll.cpp index e72b39143d..ca89db4c8a 100644 --- a/submodules/ton/tonlib-src/tdutils/td/utils/port/detail/Epoll.cpp +++ b/submodules/ton/tonlib-src/tdutils/td/utils/port/detail/Epoll.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "td/utils/port/detail/Epoll.h" @@ -109,6 +109,7 @@ void Epoll::run(int timeout_ms) { #ifdef EPOLLRDHUP if (event->events & EPOLLRDHUP) { event->events &= ~EPOLLRDHUP; + flags = flags | PollFlags::Close(); // flags |= Fd::Close; // TODO } diff --git a/submodules/ton/tonlib-src/tdutils/td/utils/port/rlimit.cpp b/submodules/ton/tonlib-src/tdutils/td/utils/port/rlimit.cpp new file mode 100644 index 0000000000..5833961c89 --- /dev/null +++ b/submodules/ton/tonlib-src/tdutils/td/utils/port/rlimit.cpp @@ -0,0 +1,102 @@ +/* + This file is part of TON Blockchain Library. + + TON Blockchain Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + TON Blockchain Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with TON Blockchain Library. If not, see . + + Copyright 2019-2020 Telegram Systems LLP +*/ +#include "rlimit.h" +#if TD_LINUX || TD_ANDROID +#include +#include +#include +#include +#endif + +namespace td { + +#if TD_PORT_POSIX + +namespace { + +int get_rlimit_type(RlimitType rlim_type) { + switch (rlim_type) { + case RlimitType::nofile: + return RLIMIT_NOFILE; + case RlimitType::rss: + return RLIMIT_RSS; + default: + UNREACHABLE(); + } +} + +} // namespace + +td::Status change_rlimit(RlimitType rlim_type, td::uint64 value, td::uint64 cap) { + if (cap && value > cap) { + return td::Status::Error("setrlimit(): bad argument"); + } + int resource = get_rlimit_type(rlim_type); + + struct rlimit r; + if (getrlimit(resource, &r) < 0) { + return td::Status::PosixError(errno, "failed getrlimit()"); + } + + if (cap) { + r.rlim_max = cap; + } else if (r.rlim_max < value) { + r.rlim_max = value; + } + r.rlim_cur = value; + if (setrlimit(resource, &r) < 0) { + return td::Status::PosixError(errno, "failed setrlimit()"); + } + return td::Status::OK(); +} + +td::Status change_maximize_rlimit(RlimitType rlim_type, td::uint64 value) { + int resource = get_rlimit_type(rlim_type); + + struct rlimit r; + if (getrlimit(resource, &r) < 0) { + return td::Status::PosixError(errno, "failed getrlimit()"); + } + + if (r.rlim_max < value) { + auto t = r; + t.rlim_cur = value; + t.rlim_max = value; + if (setrlimit(resource, &t) >= 0) { + return td::Status::OK(); + } + } + + r.rlim_cur = value < r.rlim_max ? value : r.rlim_max; + if (setrlimit(resource, &r) < 0) { + return td::Status::PosixError(errno, "failed setrlimit()"); + } + return td::Status::OK(); +} +#else +td::Status change_rlimit(RlimitType rlim, td::uint64 value) { + return td::Status::Error("setrlimit not implemented on WINDOWS"); +} +td::Status change_maximize_rlimit(RlimitType rlim, td::uint64 value) { + return td::Status::OK(); +} +#endif + +} // namespace td + diff --git a/submodules/ton/tonlib-src/tdutils/td/utils/port/rlimit.h b/submodules/ton/tonlib-src/tdutils/td/utils/port/rlimit.h new file mode 100644 index 0000000000..9f6a652463 --- /dev/null +++ b/submodules/ton/tonlib-src/tdutils/td/utils/port/rlimit.h @@ -0,0 +1,32 @@ +/* + This file is part of TON Blockchain Library. + + TON Blockchain Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + TON Blockchain Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with TON Blockchain Library. If not, see . + + Copyright 2017-2020 Telegram Systems LLP +*/ +#pragma once + +#include "td/utils/port/config.h" +#include "td/utils/port/platform.h" +#include "td/utils/Status.h" + +namespace td { + +enum class RlimitType { nofile, rss }; + +td::Status change_rlimit(RlimitType rlim_type, td::uint64 value, td::uint64 cap = 0); +td::Status change_maximize_rlimit(RlimitType rlim, td::uint64 value); + +} // namespace td diff --git a/submodules/ton/tonlib-src/tdutils/td/utils/port/user.cpp b/submodules/ton/tonlib-src/tdutils/td/utils/port/user.cpp index 859bb70311..2e77eff87f 100644 --- a/submodules/ton/tonlib-src/tdutils/td/utils/port/user.cpp +++ b/submodules/ton/tonlib-src/tdutils/td/utils/port/user.cpp @@ -1,3 +1,21 @@ +/* + This file is part of TON Blockchain Library. + + TON Blockchain Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + TON Blockchain Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with TON Blockchain Library. If not, see . + + Copyright 2017-2020 Telegram Systems LLP +*/ #include "user.h" #if TD_LINUX #include diff --git a/submodules/ton/tonlib-src/tdutils/td/utils/port/user.h b/submodules/ton/tonlib-src/tdutils/td/utils/port/user.h index 4c5d48a457..9c53c2fc2c 100644 --- a/submodules/ton/tonlib-src/tdutils/td/utils/port/user.h +++ b/submodules/ton/tonlib-src/tdutils/td/utils/port/user.h @@ -1,3 +1,21 @@ +/* + This file is part of TON Blockchain Library. + + TON Blockchain Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + TON Blockchain Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with TON Blockchain Library. If not, see . + + Copyright 2017-2020 Telegram Systems LLP +*/ #pragma once #include "td/utils/port/config.h" diff --git a/submodules/ton/tonlib-src/tdutils/test/MpmcWaiter.cpp b/submodules/ton/tonlib-src/tdutils/test/MpmcWaiter.cpp index cf75b5252d..9cb5b3635b 100644 --- a/submodules/ton/tonlib-src/tdutils/test/MpmcWaiter.cpp +++ b/submodules/ton/tonlib-src/tdutils/test/MpmcWaiter.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "td/utils/MpmcWaiter.h" #include "td/utils/port/sleep.h" @@ -25,21 +25,22 @@ #include #if !TD_THREAD_UNSUPPORTED -TEST(MpmcWaiter, stress_one_one) { +template +void test_waiter_stress_one_one() { td::Stage run; td::Stage check; std::vector threads; std::atomic value{0}; size_t write_cnt = 10; - td::unique_ptr waiter; + td::unique_ptr waiter; size_t threads_n = 2; for (size_t i = 0; i < threads_n; i++) { threads.push_back(td::thread([&, id = static_cast(i)] { for (td::uint64 round = 1; round < 100000; round++) { if (id == 0) { value = 0; - waiter = td::make_unique(); + waiter = td::make_unique(); write_cnt = td::Random::fast(1, 10); } run.wait(round * threads_n); @@ -49,17 +50,19 @@ TEST(MpmcWaiter, stress_one_one) { waiter->notify(); } } else { - int yields = 0; + typename W::Slot slot; + waiter->init_slot(slot, id); for (size_t i = 1; i <= write_cnt; i++) { while (true) { auto x = value.load(std::memory_order_relaxed); if (x >= i) { break; } - yields = waiter->wait(yields, id); + waiter->wait(slot); } - yields = waiter->stop_wait(yields, id); + waiter->stop_wait(slot); } + waiter->stop_wait(slot); } check.wait(round * threads_n); } @@ -69,7 +72,15 @@ TEST(MpmcWaiter, stress_one_one) { thread.join(); } } -TEST(MpmcWaiter, stress) { +TEST(MpmcEagerWaiter, stress_one_one) { + test_waiter_stress_one_one(); +} +TEST(MpmcSleepyWaiter, stress_one_one) { + test_waiter_stress_one_one(); +} + +template +void test_waiter_stress() { td::Stage run; td::Stage check; @@ -81,7 +92,7 @@ TEST(MpmcWaiter, stress) { size_t end_pos; size_t write_cnt; size_t threads_n = 20; - td::unique_ptr waiter; + td::unique_ptr waiter; for (size_t i = 0; i < threads_n; i++) { threads.push_back(td::thread([&, id = static_cast(i)] { for (td::uint64 round = 1; round < 1000; round++) { @@ -92,7 +103,7 @@ TEST(MpmcWaiter, stress) { end_pos = write_n * write_cnt; write_pos = 0; read_pos = 0; - waiter = td::make_unique(); + waiter = td::make_unique(); } run.wait(round * threads_n); if (id <= write_n) { @@ -104,21 +115,26 @@ TEST(MpmcWaiter, stress) { waiter->notify(); } } else if (id > 10 && id - 10 <= read_n) { - int yields = 0; + typename W::Slot slot; + waiter->init_slot(slot, id); while (true) { auto x = read_pos.load(std::memory_order_relaxed); if (x == end_pos) { + waiter->stop_wait(slot); break; } if (x == write_pos.load(std::memory_order_relaxed)) { - yields = waiter->wait(yields, id); + waiter->wait(slot); continue; } - yields = waiter->stop_wait(yields, id); + waiter->stop_wait(slot); read_pos.compare_exchange_strong(x, x + 1, std::memory_order_relaxed); } } check.wait(round * threads_n); + if (id == 0) { + waiter->close(); + } } })); } @@ -126,4 +142,10 @@ TEST(MpmcWaiter, stress) { thread.join(); } } +TEST(MpmcEagerWaiter, stress_multi) { + test_waiter_stress(); +} +TEST(MpmcSleepyWaiter, stress_multi) { + test_waiter_stress(); +} #endif // !TD_THREAD_UNSUPPORTED diff --git a/submodules/ton/tonlib-src/tdutils/test/StealingQueue.cpp b/submodules/ton/tonlib-src/tdutils/test/StealingQueue.cpp new file mode 100644 index 0000000000..6aa2aae6ba --- /dev/null +++ b/submodules/ton/tonlib-src/tdutils/test/StealingQueue.cpp @@ -0,0 +1,153 @@ +/* + This file is part of TON Blockchain source code. + + TON Blockchain is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + TON Blockchain is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TON Blockchain. If not, see . + + In addition, as a special exception, the copyright holders give permission + to link the code of portions of this program with the OpenSSL library. + You must obey the GNU General Public License in all respects for all + of the code used other than OpenSSL. If you modify file(s) with this + exception, you may extend this exception to your version of the file(s), + but you are not obligated to do so. If you do not wish to do so, delete this + exception statement from your version. If you delete this exception statement + from all source files in the program, then also delete it here. + + Copyright 2019-2020 Telegram Systems LLP +*/ +#include "td/utils/tests.h" +#include "td/utils/benchmark.h" + +#include "td/utils/StealingQueue.h" +#include "td/utils/MpmcQueue.h" + +namespace td { +TEST(StealingQueue, very_simple) { + StealingQueue q; + q.local_push(1, [](auto x) { UNREACHABLE(); }); + int x; + CHECK(q.local_pop(x)); + ASSERT_EQ(1, x); +} +TEST(AtomicRead, simple) { + td::Stage run; + td::Stage check; + + size_t threads_n = 10; + std::vector threads; + + int x{0}; + std::atomic version{0}; + + int64 res = 0; + for (size_t i = 0; i < threads_n; i++) { + threads.push_back(td::thread([&, id = static_cast(i)] { + for (uint64 round = 1; round < 10000; round++) { + if (id == 0) { + } + run.wait(round * threads_n); + if (id == 0) { + version++; + x++; + version++; + } else { + int y = 0; + auto v1 = version.load(); + y = x; + auto v2 = version.load(); + if (v1 == v2 && v1 % 2 == 0) { + res += y; + } + } + + check.wait(round * threads_n); + } + })); + } + td::do_not_optimize_away(res); + for (auto &thread : threads) { + thread.join(); + } +} +TEST(StealingQueue, simple) { + uint64 sum; + std::atomic got_sum; + + td::Stage run; + td::Stage check; + + size_t threads_n = 10; + std::vector threads; + std::vector> lq(threads_n); + MpmcQueue gq(threads_n); + + constexpr uint64 XN = 20; + uint64 x_sum[XN]; + x_sum[0] = 0; + x_sum[1] = 1; + for (uint64 i = 2; i < XN; i++) { + x_sum[i] = i + x_sum[i - 1] + x_sum[i - 2]; + } + + td::Random::Xorshift128plus rnd(123); + for (size_t i = 0; i < threads_n; i++) { + threads.push_back(td::thread([&, id = static_cast(i)] { + for (uint64 round = 1; round < 10000; round++) { + if (id == 0) { + sum = 0; + int n = rnd() % 5; + for (int j = 0; j < n; j++) { + int x = rand() % XN; + sum += x_sum[x]; + gq.push(x, id); + } + got_sum = 0; + } + run.wait(round * threads_n); + while (got_sum.load() != sum) { + auto x = [&] { + int res; + if (lq[id].local_pop(res)) { + return res; + } + if (gq.try_pop(res, id)) { + return res; + } + if (lq[id].steal(res, lq[rand() % threads_n])) { + //LOG(ERROR) << "STEAL"; + return res; + } + return 0; + }(); + if (x == 0) { + continue; + } + //LOG(ERROR) << x << " " << got_sum.load() << " " << sum; + got_sum.fetch_add(x, std::memory_order_relaxed); + lq[id].local_push(x - 1, [&](auto y) { + //LOG(ERROR) << "OVERFLOW"; + gq.push(y, id); + }); + if (x > 1) { + lq[id].local_push(x - 2, [&](auto y) { gq.push(y, id); }); + } + } + check.wait(round * threads_n); + } + })); + } + for (auto &thread : threads) { + thread.join(); + } +} +} // namespace td diff --git a/submodules/ton/tonlib-src/tdutils/test/log.cpp b/submodules/ton/tonlib-src/tdutils/test/log.cpp index 99be2d59b5..707bb07084 100644 --- a/submodules/ton/tonlib-src/tdutils/test/log.cpp +++ b/submodules/ton/tonlib-src/tdutils/test/log.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "td/utils/tests.h" #include "td/utils/FileLog.h" @@ -80,7 +80,8 @@ void bench_log(std::string name, int threads_n, F &&f) { }; TEST(Log, TsLogger) { - bench_log("NewTsFileLog", 4, [] { return td::TsFileLog::create("tmplog").move_as_ok(); }); + bench_log("NewTsFileLog", 4, + [] { return td::TsFileLog::create("tmplog", std::numeric_limits::max(), false).move_as_ok(); }); bench_log("TsFileLog", 8, [] { class FileLog : public td::LogInterface { public: diff --git a/submodules/ton/tonlib-src/tdutils/test/misc.cpp b/submodules/ton/tonlib-src/tdutils/test/misc.cpp index b3c472507f..f43fcdcc5e 100644 --- a/submodules/ton/tonlib-src/tdutils/test/misc.cpp +++ b/submodules/ton/tonlib-src/tdutils/test/misc.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "td/utils/as.h" #include "td/utils/base64.h" @@ -220,6 +220,26 @@ TEST(Misc, base64) { "Ojo7ISUiOw=="); } +TEST(Misc, base32) { + ASSERT_EQ("", base32_encode("")); + ASSERT_EQ("me", base32_encode("a")); + base32_decode("me").ensure(); + ASSERT_EQ("mfra", base32_encode("ab")); + ASSERT_EQ("mfrgg", base32_encode("abc")); + ASSERT_EQ("mfrggza", base32_encode("abcd")); + ASSERT_EQ("mfrggzdg", base32_encode("abcdf")); + ASSERT_EQ("mfrggzdgm4", base32_encode("abcdfg")); + for (int l = 0; l < 300000; l += l / 20 + l / 1000 * 500 + 1) { + for (int t = 0; t < 10; t++) { + string s = rand_string(std::numeric_limits::min(), std::numeric_limits::max(), l); + auto encoded = base32_encode(s); + auto decoded = base32_decode(encoded); + ASSERT_TRUE(decoded.is_ok()); + ASSERT_TRUE(decoded.ok() == s); + } + } +} + TEST(Misc, to_integer) { ASSERT_EQ(to_integer("-1234567"), -1234567); ASSERT_EQ(to_integer("-1234567"), -1234567); @@ -570,6 +590,10 @@ static void test_full_split(Slice str, vector expected) { ASSERT_EQ(expected, td::full_split(str)); } +static void test_full_split(Slice str, char c, size_t max_parts, vector expected) { + ASSERT_EQ(expected, td::full_split(str, c, max_parts)); +} + TEST(Misc, full_split) { test_full_split("", {}); test_full_split(" ", {"", ""}); @@ -585,6 +609,7 @@ TEST(Misc, full_split) { test_full_split(" abcdef ", {"", "abcdef", ""}); test_full_split(" ab cd ef ", {"", "ab", "cd", "ef", ""}); test_full_split(" ab cd ef ", {"", "", "ab", "", "cd", "", "ef", "", ""}); + test_full_split("ab cd ef gh", ' ', 3, {"ab", "cd", "ef gh"}); } TEST(Misc, StringBuilder) { diff --git a/submodules/ton/tonlib-src/terminal/terminal.cpp b/submodules/ton/tonlib-src/terminal/terminal.cpp index c0b44e557e..9b4ae37418 100644 --- a/submodules/ton/tonlib-src/terminal/terminal.cpp +++ b/submodules/ton/tonlib-src/terminal/terminal.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "terminal.hpp" #include "td/utils/port/StdStreams.h" @@ -29,11 +29,11 @@ namespace td { void TerminalLogInterface::append(CSlice slice, int log_level) { - auto instance_ = TerminalIOImpl::instance(); - if (!instance_) { + auto instance = TerminalIOImpl::instance(); + if (!instance) { default_log_interface->append(slice, log_level); } else { - instance_->deactivate_readline(); + instance->deactivate_readline(); std::string color; if (log_level == 0 || log_level == 1) { color = TC_RED; @@ -43,7 +43,7 @@ void TerminalLogInterface::append(CSlice slice, int log_level) { color = TC_GREEN; } td::TsCerr() << color << slice << TC_EMPTY; - instance_->reactivate_readline(); + instance->reactivate_readline(); if (log_level == VERBOSITY_NAME(FATAL)) { process_fatal_error(slice); } @@ -82,6 +82,16 @@ void TerminalIOImpl::output_line(std::string line) { reactivate_readline(); } +void TerminalIOImpl::output_line_stderr(std::string line) { + deactivate_readline(); + if (use_readline_) { + Stdout().write(line).ensure(); + } else { + Stderr().write(line).ensure(); + } + reactivate_readline(); +} + void TerminalIOImpl::start_up() { instance_ = this; self_ = actor_id(this); @@ -206,17 +216,17 @@ void TerminalIOImpl::s_line(char *line) { LOG(FATAL) << "Closed"; return; } - CHECK(instance_); + CHECK(instance); if (*line) { add_history(line); } - instance_->line_cb(line); + instance()->line_cb(line); rl_free(line); #endif } int TerminalIOImpl::s_stdin_getc(FILE *) { - return instance_->stdin_getc(); + return instance()->stdin_getc(); } void TerminalIOImpl::set_log_interface() { @@ -240,32 +250,81 @@ void TerminalIOImpl::line_cb(std::string cmd) { cmd_queue_.push(td::BufferSlice{std::move(cmd)}); } -void TerminalIO::output(std::string line) { - auto instance_ = TerminalIOImpl::instance(); - if (!instance_) { - std::cout << line; - } else { - instance_->deactivate_readline(); - td::TsCerr() << line; - instance_->reactivate_readline(); +void TerminalIO::output_stdout(td::Slice slice, double max_wait) { + auto &fd = td::Stdout(); + if (fd.empty()) { + return; + } + double end_time = 0; + while (!slice.empty()) { + auto res = fd.write(slice); + if (res.is_error()) { + if (res.error().code() == EPIPE) { + break; + } + // Resource temporary unavailable + if (end_time == 0) { + end_time = Time::now() + max_wait; + } else if (Time::now() > end_time) { + break; + } + continue; + } + slice.remove_prefix(res.ok()); } } +void TerminalIO::output(std::string line) { + output(td::Slice(line)); +} + void TerminalIO::output(td::Slice line) { - auto instance_ = TerminalIOImpl::instance(); - if (!instance_) { + auto instance = TerminalIOImpl::instance(); + if (!instance) { + output_stdout(line, 10.0); + } else { + instance->deactivate_readline(); + output_stdout(line, 10.0); + instance->reactivate_readline(); + } +} + +void TerminalIO::output_stderr(std::string line) { + output_stderr(td::Slice(line)); +} + +void TerminalIO::output_stderr(td::Slice line) { + auto instance = TerminalIOImpl::instance(); + if (!instance) { td::TsCerr() << line; } else { - instance_->deactivate_readline(); - td::TsCerr() << line; - instance_->reactivate_readline(); + if (instance->readline_used()) { + instance->deactivate_readline(); + output_stdout(line, 0.01); + instance->reactivate_readline(); + } else { + td::TsCerr() << line; + } + } +} + +void TerminalIOOutputter::flush() { + if (buffer_) { + CHECK(sb_); + if (!sb_->as_cslice().empty()) { + if (is_err_) { + TerminalIO::output_stderr(sb_->as_cslice()); + } else { + TerminalIO::output(sb_->as_cslice()); + } + } + sb_->clear(); } } TerminalIOOutputter::~TerminalIOOutputter() { if (buffer_) { - CHECK(sb_); - TerminalIO::output(sb_->as_cslice()); + flush(); delete[] buffer_; } } diff --git a/submodules/ton/tonlib-src/terminal/terminal.h b/submodules/ton/tonlib-src/terminal/terminal.h index 49a7d7b324..baa5df2e7e 100644 --- a/submodules/ton/tonlib-src/terminal/terminal.h +++ b/submodules/ton/tonlib-src/terminal/terminal.h @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once @@ -29,8 +29,10 @@ namespace td { class TerminalIOOutputter { public: static const size_t BUFFER_SIZE = 128 * 1024; - TerminalIOOutputter() - : buffer_(new char[BUFFER_SIZE]), sb_(std::make_unique(td::MutableSlice{buffer_, BUFFER_SIZE})) { + TerminalIOOutputter(bool is_err) + : buffer_(new char[BUFFER_SIZE]) + , is_err_(is_err) + , sb_(std::make_unique(td::MutableSlice{buffer_, BUFFER_SIZE}, true)) { } TerminalIOOutputter(TerminalIOOutputter &&X) = default; @@ -54,10 +56,12 @@ class TerminalIOOutputter { bool is_error() const { return sb_->is_error(); } + void flush(); ~TerminalIOOutputter(); private: char *buffer_; + bool is_err_; std::unique_ptr sb_; }; @@ -75,11 +79,19 @@ class TerminalIO : public actor::Actor { virtual void update_callback(std::unique_ptr callback) = 0; static void output(std::string line); static void output(td::Slice slice); + static void output_stderr(std::string line); + static void output_stderr(td::Slice slice); + static void output_stdout(td::Slice line, double max_wait); static TerminalIOOutputter out() { - return TerminalIOOutputter{}; + return TerminalIOOutputter{false}; + } + static TerminalIOOutputter err() { + return TerminalIOOutputter{true}; } virtual void output_line(std::string line) = 0; + virtual void output_line_stderr(std::string line) = 0; virtual void set_log_interface() = 0; + virtual bool readline_used() const = 0; static td::actor::ActorOwn create(std::string prompt, bool use_readline, std::unique_ptr callback); diff --git a/submodules/ton/tonlib-src/terminal/terminal.hpp b/submodules/ton/tonlib-src/terminal/terminal.hpp index 637d753b45..481b7a5088 100644 --- a/submodules/ton/tonlib-src/terminal/terminal.hpp +++ b/submodules/ton/tonlib-src/terminal/terminal.hpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once @@ -45,6 +45,10 @@ class TerminalIOImpl : public TerminalIO, td::ObserverBase { void deactivate_readline(); void reactivate_readline(); void output_line(std::string line) override; + void output_line_stderr(std::string line) override; + bool readline_used() const override { + return use_readline_; + } void set_log_interface() override; //void read_line(); void loop() override; diff --git a/submodules/ton/tonlib-src/test/regression-tests.ans b/submodules/ton/tonlib-src/test/regression-tests.ans index 29e26328dc..f58e3ee10d 100644 --- a/submodules/ton/tonlib-src/test/regression-tests.ans +++ b/submodules/ton/tonlib-src/test/regression-tests.ans @@ -7,7 +7,7 @@ Test_Fift_bug_newlize_default e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca4 Test_Fift_bug_ufits_default 51bf5a9f1ed7633a193f6fdd17a7a3af8e032dfe72a9669c85e8639aa8a7c195 Test_Fift_contfrac_default 09ebce5c91bcb70696c6fb6981d82dc3b9e3444dab608a7a1b044c0ddd778a96 Test_Fift_test_default 4e44b3382963ec89f7b5c8f2ebd85da3bc8aebad5b49f5b11b14075061477b4d -Test_Fift_test_dict_default 480d22a6ec25a232febf4eec8ff64747573f79721327e7ff3b1aa7ea4921bbb4 +Test_Fift_test_dict_default a9c8cbcfdece5573185022cea07f59f1bc404e5d879e5157a5745757f8ee0525 Test_Fift_test_fixed_default 278a19d56b773102caf5c1fe2997ea6c8d0d9e720eff8503feede6398a197eec Test_Fift_test_sort2_default 9b57d47e6a10e7d1bbb565db35400debf2f963031f434742a702ec76555a5d3a Test_Fift_test_sort_default 9b57d47e6a10e7d1bbb565db35400debf2f963031f434742a702ec76555a5d3a @@ -15,15 +15,15 @@ Test_Fift_testvm2_default 8a6e35fc0224398be9d2de39d31c86ea96965ef1eca2aa9e0af230 Test_Fift_testvm3_default 3c1b77471c5fd914ed8b5f528b9faed618e278693f5030b953ff150e543864ae Test_Fift_testvm4_default 8a6e35fc0224398be9d2de39d31c86ea96965ef1eca2aa9e0af2303150ed4a7b Test_Fift_testvm4a_default 523b561d6bf2f5ebb26a755e687bfbda8e33462c98e9978119755f79a086cf5e -Test_Fift_testvm4b_default daf8567bd58f05c10bb6596cea33b63e1061fa02dd5560db18ff22f96736f0d5 +Test_Fift_testvm4b_default e6d16e7217d0b2a3f0b38be0e3af0e28a70c925ccbc1c4d9890e25b8973e565a Test_Fift_testvm4c_default 2bbd67831d90bceaae29546ee3a58c4d376c2e8fb6a5b8ea2eae3ab8787e063e -Test_Fift_testvm4d_default 32eee098378e64c938dea09990287a349d0d8f6aabb7360535c782a958cd5fea +Test_Fift_testvm4d_default 9e8de54cfc3676ba4e817a4bd0367655d3514b898fecb3e71178e5aff8e35f83 Test_Fift_testvm5_default bab109acfdf626a192171d74c69c3176d661a8dedf730aea616d4997b98830f1 Test_Fift_testvm6_default dd6353c8f3f21cf62a4769ee1f3daaec46f43fd633ffb84c5d6535b120af9027 Test_Fift_testvm7_default 77f54b6c8c9a728d262e912efcc347de7014a37d08793c3adeac8b96fe063342 Test_Fift_testvm8_default 17c9e2205ccecfd8549328b4a501d07dde0336899a7a496e747e1032ad5efff9 Test_Fift_testvm_default ee4cbfec76c050b6de7877cfc39817d594cd1e175b6265b76fb642e30b940437 -Test_Fift_testvmprog_default 3aeebf868c0492f2bafe339505751449e9d258bf25ea5d956efe70c6fce408ed +Test_Fift_testvmprog_default e5d0b2c68ee568280877c8495be558bfd0054ca5d99a99eebb525bbeca8a65af Test_RefInt_main_default 768493e0aef8e09a401a6d369edd1ef503a9215fb09dc460f52b27a8bde767cb Test_VM_assert_code_not_null_default 05bc07e129181c972b976442f200de9487dee8bfb5ac53dd36ff61c5d4d4291d Test_VM_assert_extract_minmax_key_default c352309c61bdf62ba7a0ba7280d303c88b0696fe7efa550c05feb2c662275297 diff --git a/submodules/ton/tonlib-src/test/test-hello-world.cpp b/submodules/ton/tonlib-src/test/test-hello-world.cpp index 427528f108..3a659f578d 100644 --- a/submodules/ton/tonlib-src/test/test-hello-world.cpp +++ b/submodules/ton/tonlib-src/test/test-hello-world.cpp @@ -31,6 +31,7 @@ #include "auto/tl/ton_api_json.h" #include "tl/tl_json.h" +#include "td/utils/Random.h" namespace { std::string config = R"json( @@ -135,4 +136,25 @@ int main() { return res; }; test_tl_json(ton::ton_api::make_object(create_vector_bytes())); + + td::Bits256 x; + td::Random::secure_bytes(x.as_slice()); + + auto s = x.to_hex(); + + auto v = td::hex_decode(s).move_as_ok(); + + auto w = td::buffer_to_hex(x.as_slice()); + + td::Bits256 y; + y.as_slice().copy_from(v); + + CHECK(x == y); + + auto w2 = td::hex_decode(w).move_as_ok(); + td::Bits256 z; + z.as_slice().copy_from(w2); + + LOG_CHECK(x == z) << s << " " << w; + return 0; } diff --git a/submodules/ton/tonlib-src/tl/generate/auto/tl/lite_api.cpp b/submodules/ton/tonlib-src/tl/generate/auto/tl/lite_api.cpp index 0b4ab90328..4e111c93b7 100644 --- a/submodules/ton/tonlib-src/tl/generate/auto/tl/lite_api.cpp +++ b/submodules/ton/tonlib-src/tl/generate/auto/tl/lite_api.cpp @@ -58,6 +58,8 @@ object_ptr Object::fetch(td::TlParser &p) { return liteServer_masterchainInfoExt::fetch(p); case liteServer_partialBlockProof::ID: return liteServer_partialBlockProof::fetch(p); + case liteServer_runMethodResult::ID: + return liteServer_runMethodResult::fetch(p); case liteServer_sendMsgStatus::ID: return liteServer_sendMsgStatus::fetch(p); case liteServer_shardInfo::ID: @@ -74,6 +76,8 @@ object_ptr Object::fetch(td::TlParser &p) { return liteServer_transactionInfo::fetch(p); case liteServer_transactionList::ID: return liteServer_transactionList::fetch(p); + case liteServer_validatorStats::ID: + return liteServer_validatorStats::fetch(p); case liteServer_version::ID: return liteServer_version::fetch(p); case liteServer_debug_verbosity::ID: @@ -122,6 +126,8 @@ object_ptr Function::fetch(td::TlParser &p) { return liteServer_getTime::fetch(p); case liteServer_getTransactions::ID: return liteServer_getTransactions::fetch(p); + case liteServer_getValidatorStats::ID: + return liteServer_getValidatorStats::fetch(p); case liteServer_getVersion::ID: return liteServer_getVersion::fetch(p); case liteServer_listBlockTransactions::ID: @@ -132,6 +138,8 @@ object_ptr Function::fetch(td::TlParser &p) { return liteServer_query::fetch(p); case liteServer_queryPrefix::ID: return liteServer_queryPrefix::fetch(p); + case liteServer_runSmcMethod::ID: + return liteServer_runSmcMethod::fetch(p); case liteServer_sendMessage::ID: return liteServer_sendMessage::fetch(p); case liteServer_waitMasterchainSeqno::ID: @@ -1098,6 +1106,101 @@ void liteServer_partialBlockProof::store(td::TlStorerToString &s, const char *fi } } +liteServer_runMethodResult::liteServer_runMethodResult() + : mode_() + , id_() + , shardblk_() + , shard_proof_() + , proof_() + , state_proof_() + , init_c7_() + , lib_extras_() + , exit_code_() + , result_() +{} + +liteServer_runMethodResult::liteServer_runMethodResult(std::int32_t mode_, object_ptr &&id_, object_ptr &&shardblk_, td::BufferSlice &&shard_proof_, td::BufferSlice &&proof_, td::BufferSlice &&state_proof_, td::BufferSlice &&init_c7_, td::BufferSlice &&lib_extras_, std::int32_t exit_code_, td::BufferSlice &&result_) + : mode_(mode_) + , id_(std::move(id_)) + , shardblk_(std::move(shardblk_)) + , shard_proof_(std::move(shard_proof_)) + , proof_(std::move(proof_)) + , state_proof_(std::move(state_proof_)) + , init_c7_(std::move(init_c7_)) + , lib_extras_(std::move(lib_extras_)) + , exit_code_(exit_code_) + , result_(std::move(result_)) +{} + +const std::int32_t liteServer_runMethodResult::ID; + +object_ptr liteServer_runMethodResult::fetch(td::TlParser &p) { +#define FAIL(error) p.set_error(error); return nullptr; + object_ptr res = make_object(); + std::int32_t var0; + if ((var0 = res->mode_ = TlFetchInt::parse(p)) < 0) { FAIL("Variable of type # can't be negative"); } + res->id_ = TlFetchObject::parse(p); + res->shardblk_ = TlFetchObject::parse(p); + if (var0 & 1) { res->shard_proof_ = TlFetchBytes::parse(p); } + if (var0 & 1) { res->proof_ = TlFetchBytes::parse(p); } + if (var0 & 2) { res->state_proof_ = TlFetchBytes::parse(p); } + if (var0 & 8) { res->init_c7_ = TlFetchBytes::parse(p); } + if (var0 & 16) { res->lib_extras_ = TlFetchBytes::parse(p); } + res->exit_code_ = TlFetchInt::parse(p); + if (var0 & 4) { res->result_ = TlFetchBytes::parse(p); } + if (p.get_error()) { FAIL(""); } + return res; +#undef FAIL +} + +void liteServer_runMethodResult::store(td::TlStorerCalcLength &s) const { + (void)sizeof(s); + std::int32_t var0; + TlStoreBinary::store((var0 = mode_), s); + TlStoreObject::store(id_, s); + TlStoreObject::store(shardblk_, s); + if (var0 & 1) { TlStoreString::store(shard_proof_, s); } + if (var0 & 1) { TlStoreString::store(proof_, s); } + if (var0 & 2) { TlStoreString::store(state_proof_, s); } + if (var0 & 8) { TlStoreString::store(init_c7_, s); } + if (var0 & 16) { TlStoreString::store(lib_extras_, s); } + TlStoreBinary::store(exit_code_, s); + if (var0 & 4) { TlStoreString::store(result_, s); } +} + +void liteServer_runMethodResult::store(td::TlStorerUnsafe &s) const { + (void)sizeof(s); + std::int32_t var0; + TlStoreBinary::store((var0 = mode_), s); + TlStoreObject::store(id_, s); + TlStoreObject::store(shardblk_, s); + if (var0 & 1) { TlStoreString::store(shard_proof_, s); } + if (var0 & 1) { TlStoreString::store(proof_, s); } + if (var0 & 2) { TlStoreString::store(state_proof_, s); } + if (var0 & 8) { TlStoreString::store(init_c7_, s); } + if (var0 & 16) { TlStoreString::store(lib_extras_, s); } + TlStoreBinary::store(exit_code_, s); + if (var0 & 4) { TlStoreString::store(result_, s); } +} + +void liteServer_runMethodResult::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "liteServer_runMethodResult"); + std::int32_t var0; + s.store_field("mode", (var0 = mode_)); + if (id_ == nullptr) { s.store_field("id", "null"); } else { id_->store(s, "id"); } + if (shardblk_ == nullptr) { s.store_field("shardblk", "null"); } else { shardblk_->store(s, "shardblk"); } + if (var0 & 1) { s.store_bytes_field("shard_proof", shard_proof_); } + if (var0 & 1) { s.store_bytes_field("proof", proof_); } + if (var0 & 2) { s.store_bytes_field("state_proof", state_proof_); } + if (var0 & 8) { s.store_bytes_field("init_c7", init_c7_); } + if (var0 & 16) { s.store_bytes_field("lib_extras", lib_extras_); } + s.store_field("exit_code", exit_code_); + if (var0 & 4) { s.store_bytes_field("result", result_); } + s.store_class_end(); + } +} + liteServer_sendMsgStatus::liteServer_sendMsgStatus() : status_() {} @@ -1483,6 +1586,77 @@ void liteServer_transactionList::store(td::TlStorerToString &s, const char *fiel } } +liteServer_validatorStats::liteServer_validatorStats() + : mode_() + , id_() + , count_() + , complete_() + , state_proof_() + , data_proof_() +{} + +liteServer_validatorStats::liteServer_validatorStats(std::int32_t mode_, object_ptr &&id_, std::int32_t count_, bool complete_, td::BufferSlice &&state_proof_, td::BufferSlice &&data_proof_) + : mode_(mode_) + , id_(std::move(id_)) + , count_(count_) + , complete_(complete_) + , state_proof_(std::move(state_proof_)) + , data_proof_(std::move(data_proof_)) +{} + +const std::int32_t liteServer_validatorStats::ID; + +object_ptr liteServer_validatorStats::fetch(td::TlParser &p) { +#define FAIL(error) p.set_error(error); return nullptr; + object_ptr res = make_object(); + std::int32_t var0; + if ((var0 = res->mode_ = TlFetchInt::parse(p)) < 0) { FAIL("Variable of type # can't be negative"); } + res->id_ = TlFetchObject::parse(p); + res->count_ = TlFetchInt::parse(p); + res->complete_ = TlFetchBool::parse(p); + res->state_proof_ = TlFetchBytes::parse(p); + res->data_proof_ = TlFetchBytes::parse(p); + if (p.get_error()) { FAIL(""); } + return res; +#undef FAIL +} + +void liteServer_validatorStats::store(td::TlStorerCalcLength &s) const { + (void)sizeof(s); + std::int32_t var0; + TlStoreBinary::store((var0 = mode_), s); + TlStoreObject::store(id_, s); + TlStoreBinary::store(count_, s); + TlStoreBool::store(complete_, s); + TlStoreString::store(state_proof_, s); + TlStoreString::store(data_proof_, s); +} + +void liteServer_validatorStats::store(td::TlStorerUnsafe &s) const { + (void)sizeof(s); + std::int32_t var0; + TlStoreBinary::store((var0 = mode_), s); + TlStoreObject::store(id_, s); + TlStoreBinary::store(count_, s); + TlStoreBool::store(complete_, s); + TlStoreString::store(state_proof_, s); + TlStoreString::store(data_proof_, s); +} + +void liteServer_validatorStats::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "liteServer_validatorStats"); + std::int32_t var0; + s.store_field("mode", (var0 = mode_)); + if (id_ == nullptr) { s.store_field("id", "null"); } else { id_->store(s, "id"); } + s.store_field("count", count_); + s.store_field("complete", complete_); + s.store_bytes_field("state_proof", state_proof_); + s.store_bytes_field("data_proof", data_proof_); + s.store_class_end(); + } +} + liteServer_version::liteServer_version() : mode_() , version_() @@ -2462,6 +2636,76 @@ liteServer_getTransactions::ReturnType liteServer_getTransactions::fetch_result( #undef FAIL } +liteServer_getValidatorStats::liteServer_getValidatorStats() + : mode_() + , id_() + , limit_() + , start_after_() + , modified_after_() +{} + +liteServer_getValidatorStats::liteServer_getValidatorStats(std::int32_t mode_, object_ptr &&id_, std::int32_t limit_, td::Bits256 const &start_after_, std::int32_t modified_after_) + : mode_(mode_) + , id_(std::move(id_)) + , limit_(limit_) + , start_after_(start_after_) + , modified_after_(modified_after_) +{} + +const std::int32_t liteServer_getValidatorStats::ID; + +object_ptr liteServer_getValidatorStats::fetch(td::TlParser &p) { +#define FAIL(error) p.set_error(error); return nullptr; + object_ptr res = make_object(); + std::int32_t var0; + if ((var0 = res->mode_ = TlFetchInt::parse(p)) < 0) { FAIL("Variable of type # can't be negative"); } + res->id_ = TlFetchObject::parse(p); + res->limit_ = TlFetchInt::parse(p); + if (var0 & 1) { res->start_after_ = TlFetchInt256::parse(p); } + if (var0 & 4) { res->modified_after_ = TlFetchInt::parse(p); } + if (p.get_error()) { FAIL(""); } + return res; +#undef FAIL +} + +void liteServer_getValidatorStats::store(td::TlStorerCalcLength &s) const { + (void)sizeof(s); + s.store_binary(152721596); + TlStoreBinary::store((var0 = mode_), s); + TlStoreObject::store(id_, s); + TlStoreBinary::store(limit_, s); + if (var0 & 1) { TlStoreBinary::store(start_after_, s); } + if (var0 & 4) { TlStoreBinary::store(modified_after_, s); } +} + +void liteServer_getValidatorStats::store(td::TlStorerUnsafe &s) const { + (void)sizeof(s); + s.store_binary(152721596); + TlStoreBinary::store((var0 = mode_), s); + TlStoreObject::store(id_, s); + TlStoreBinary::store(limit_, s); + if (var0 & 1) { TlStoreBinary::store(start_after_, s); } + if (var0 & 4) { TlStoreBinary::store(modified_after_, s); } +} + +void liteServer_getValidatorStats::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "liteServer_getValidatorStats"); + s.store_field("mode", (var0 = mode_)); + if (id_ == nullptr) { s.store_field("id", "null"); } else { id_->store(s, "id"); } + s.store_field("limit", limit_); + if (var0 & 1) { s.store_field("start_after", start_after_); } + if (var0 & 4) { s.store_field("modified_after", modified_after_); } + s.store_class_end(); + } +} + +liteServer_getValidatorStats::ReturnType liteServer_getValidatorStats::fetch_result(td::TlParser &p) { +#define FAIL(error) p.set_error(error); return ReturnType() + return TlFetchBoxed, -1174956328>::parse(p); +#undef FAIL +} + liteServer_getVersion::liteServer_getVersion() { } @@ -2727,6 +2971,76 @@ liteServer_queryPrefix::ReturnType liteServer_queryPrefix::fetch_result(td::TlPa #undef FAIL } +liteServer_runSmcMethod::liteServer_runSmcMethod() + : mode_() + , id_() + , account_() + , method_id_() + , params_() +{} + +liteServer_runSmcMethod::liteServer_runSmcMethod(std::int32_t mode_, object_ptr &&id_, object_ptr &&account_, std::int64_t method_id_, td::BufferSlice &¶ms_) + : mode_(mode_) + , id_(std::move(id_)) + , account_(std::move(account_)) + , method_id_(method_id_) + , params_(std::move(params_)) +{} + +const std::int32_t liteServer_runSmcMethod::ID; + +object_ptr liteServer_runSmcMethod::fetch(td::TlParser &p) { +#define FAIL(error) p.set_error(error); return nullptr; + object_ptr res = make_object(); + std::int32_t var0; + if ((var0 = res->mode_ = TlFetchInt::parse(p)) < 0) { FAIL("Variable of type # can't be negative"); } + res->id_ = TlFetchObject::parse(p); + res->account_ = TlFetchObject::parse(p); + res->method_id_ = TlFetchLong::parse(p); + res->params_ = TlFetchBytes::parse(p); + if (p.get_error()) { FAIL(""); } + return res; +#undef FAIL +} + +void liteServer_runSmcMethod::store(td::TlStorerCalcLength &s) const { + (void)sizeof(s); + s.store_binary(1556504018); + TlStoreBinary::store((var0 = mode_), s); + TlStoreObject::store(id_, s); + TlStoreObject::store(account_, s); + TlStoreBinary::store(method_id_, s); + TlStoreString::store(params_, s); +} + +void liteServer_runSmcMethod::store(td::TlStorerUnsafe &s) const { + (void)sizeof(s); + s.store_binary(1556504018); + TlStoreBinary::store((var0 = mode_), s); + TlStoreObject::store(id_, s); + TlStoreObject::store(account_, s); + TlStoreBinary::store(method_id_, s); + TlStoreString::store(params_, s); +} + +void liteServer_runSmcMethod::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "liteServer_runSmcMethod"); + s.store_field("mode", (var0 = mode_)); + if (id_ == nullptr) { s.store_field("id", "null"); } else { id_->store(s, "id"); } + if (account_ == nullptr) { s.store_field("account", "null"); } else { account_->store(s, "account"); } + s.store_field("method_id", method_id_); + s.store_bytes_field("params", params_); + s.store_class_end(); + } +} + +liteServer_runSmcMethod::ReturnType liteServer_runSmcMethod::fetch_result(td::TlParser &p) { +#define FAIL(error) p.set_error(error); return ReturnType() + return TlFetchBoxed, -1550163605>::parse(p); +#undef FAIL +} + liteServer_sendMessage::liteServer_sendMessage() : body_() {} diff --git a/submodules/ton/tonlib-src/tl/generate/auto/tl/lite_api.h b/submodules/ton/tonlib-src/tl/generate/auto/tl/lite_api.h index a4a67f3c22..65daf24c62 100644 --- a/submodules/ton/tonlib-src/tl/generate/auto/tl/lite_api.h +++ b/submodules/ton/tonlib-src/tl/generate/auto/tl/lite_api.h @@ -84,6 +84,8 @@ class liteServer_masterchainInfoExt; class liteServer_partialBlockProof; +class liteServer_runMethodResult; + class liteServer_sendMsgStatus; class liteServer_shardInfo; @@ -100,6 +102,8 @@ class liteServer_transactionInfo; class liteServer_transactionList; +class liteServer_validatorStats; + class liteServer_version; class liteServer_debug_verbosity; @@ -581,6 +585,38 @@ class liteServer_partialBlockProof final : public Object { void store(td::TlStorerToString &s, const char *field_name) const final; }; +class liteServer_runMethodResult final : public Object { + public: + std::int32_t mode_; + object_ptr id_; + object_ptr shardblk_; + td::BufferSlice shard_proof_; + td::BufferSlice proof_; + td::BufferSlice state_proof_; + td::BufferSlice init_c7_; + td::BufferSlice lib_extras_; + std::int32_t exit_code_; + td::BufferSlice result_; + enum Flags : std::int32_t {SHARD_PROOF_MASK = 1, PROOF_MASK = 1, STATE_PROOF_MASK = 2, INIT_C7_MASK = 8, LIB_EXTRAS_MASK = 16, RESULT_MASK = 4}; + + liteServer_runMethodResult(); + + liteServer_runMethodResult(std::int32_t mode_, object_ptr &&id_, object_ptr &&shardblk_, td::BufferSlice &&shard_proof_, td::BufferSlice &&proof_, td::BufferSlice &&state_proof_, td::BufferSlice &&init_c7_, td::BufferSlice &&lib_extras_, std::int32_t exit_code_, td::BufferSlice &&result_); + + static const std::int32_t ID = -1550163605; + std::int32_t get_id() const final { + return ID; + } + + static object_ptr fetch(td::TlParser &p); + + void store(td::TlStorerCalcLength &s) const final; + + void store(td::TlStorerUnsafe &s) const final; + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + class liteServer_sendMsgStatus final : public Object { public: std::int32_t status_; @@ -785,6 +821,33 @@ class liteServer_transactionList final : public Object { void store(td::TlStorerToString &s, const char *field_name) const final; }; +class liteServer_validatorStats final : public Object { + public: + std::int32_t mode_; + object_ptr id_; + std::int32_t count_; + bool complete_; + td::BufferSlice state_proof_; + td::BufferSlice data_proof_; + + liteServer_validatorStats(); + + liteServer_validatorStats(std::int32_t mode_, object_ptr &&id_, std::int32_t count_, bool complete_, td::BufferSlice &&state_proof_, td::BufferSlice &&data_proof_); + + static const std::int32_t ID = -1174956328; + std::int32_t get_id() const final { + return ID; + } + + static object_ptr fetch(td::TlParser &p); + + void store(td::TlStorerCalcLength &s) const final; + + void store(td::TlStorerUnsafe &s) const final; + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + class liteServer_version final : public Object { public: std::int32_t mode_; @@ -1310,6 +1373,38 @@ class liteServer_getTransactions final : public Function { static ReturnType fetch_result(td::TlParser &p); }; +class liteServer_getValidatorStats final : public Function { + public: + std::int32_t mode_; + object_ptr id_; + std::int32_t limit_; + td::Bits256 start_after_; + std::int32_t modified_after_; + enum Flags : std::int32_t {START_AFTER_MASK = 1, MODIFIED_AFTER_MASK = 4}; + mutable std::int32_t var0; + + liteServer_getValidatorStats(); + + liteServer_getValidatorStats(std::int32_t mode_, object_ptr &&id_, std::int32_t limit_, td::Bits256 const &start_after_, std::int32_t modified_after_); + + static const std::int32_t ID = 152721596; + std::int32_t get_id() const final { + return ID; + } + + using ReturnType = object_ptr; + + static object_ptr fetch(td::TlParser &p); + + void store(td::TlStorerCalcLength &s) const final; + + void store(td::TlStorerUnsafe &s) const final; + + void store(td::TlStorerToString &s, const char *field_name) const final; + + static ReturnType fetch_result(td::TlParser &p); +}; + class liteServer_getVersion final : public Function { public: @@ -1453,6 +1548,37 @@ class liteServer_queryPrefix final : public Function { static ReturnType fetch_result(td::TlParser &p); }; +class liteServer_runSmcMethod final : public Function { + public: + std::int32_t mode_; + object_ptr id_; + object_ptr account_; + std::int64_t method_id_; + td::BufferSlice params_; + mutable std::int32_t var0; + + liteServer_runSmcMethod(); + + liteServer_runSmcMethod(std::int32_t mode_, object_ptr &&id_, object_ptr &&account_, std::int64_t method_id_, td::BufferSlice &¶ms_); + + static const std::int32_t ID = 1556504018; + std::int32_t get_id() const final { + return ID; + } + + using ReturnType = object_ptr; + + static object_ptr fetch(td::TlParser &p); + + void store(td::TlStorerCalcLength &s) const final; + + void store(td::TlStorerUnsafe &s) const final; + + void store(td::TlStorerToString &s, const char *field_name) const final; + + static ReturnType fetch_result(td::TlParser &p); +}; + class liteServer_sendMessage final : public Function { public: td::BufferSlice body_; diff --git a/submodules/ton/tonlib-src/tl/generate/auto/tl/lite_api.hpp b/submodules/ton/tonlib-src/tl/generate/auto/tl/lite_api.hpp index 9c9062b427..540dfb6d49 100644 --- a/submodules/ton/tonlib-src/tl/generate/auto/tl/lite_api.hpp +++ b/submodules/ton/tonlib-src/tl/generate/auto/tl/lite_api.hpp @@ -65,6 +65,9 @@ bool downcast_call(Object &obj, const T &func) { case liteServer_partialBlockProof::ID: func(static_cast(obj)); return true; + case liteServer_runMethodResult::ID: + func(static_cast(obj)); + return true; case liteServer_sendMsgStatus::ID: func(static_cast(obj)); return true; @@ -89,6 +92,9 @@ bool downcast_call(Object &obj, const T &func) { case liteServer_transactionList::ID: func(static_cast(obj)); return true; + case liteServer_validatorStats::ID: + func(static_cast(obj)); + return true; case liteServer_version::ID: func(static_cast(obj)); return true; @@ -160,6 +166,9 @@ bool downcast_call(Function &obj, const T &func) { case liteServer_getTransactions::ID: func(static_cast(obj)); return true; + case liteServer_getValidatorStats::ID: + func(static_cast(obj)); + return true; case liteServer_getVersion::ID: func(static_cast(obj)); return true; @@ -175,6 +184,9 @@ bool downcast_call(Function &obj, const T &func) { case liteServer_queryPrefix::ID: func(static_cast(obj)); return true; + case liteServer_runSmcMethod::ID: + func(static_cast(obj)); + return true; case liteServer_sendMessage::ID: func(static_cast(obj)); return true; diff --git a/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api.cpp b/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api.cpp index 5c8b605177..b23e07ced9 100644 --- a/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api.cpp +++ b/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api.cpp @@ -212,8 +212,20 @@ object_ptr Object::fetch(td::TlParser &p) { return db_filedb_key_signatures::fetch(p); case db_filedb_key_candidate::ID: return db_filedb_key_candidate::fetch(p); + case db_filedb_key_blockInfo::ID: + return db_filedb_key_blockInfo::fetch(p); case db_filedb_value::ID: return db_filedb_value::fetch(p); + case db_files_index_key::ID: + return db_files_index_key::fetch(p); + case db_files_package_key::ID: + return db_files_package_key::fetch(p); + case db_files_index_value::ID: + return db_files_index_value::fetch(p); + case db_files_package_firstBlock::ID: + return db_files_package_firstBlock::fetch(p); + case db_files_package_value::ID: + return db_files_package_value::fetch(p); case db_lt_el_key::ID: return db_lt_el_key::fetch(p); case db_lt_desc_key::ID: @@ -242,6 +254,8 @@ object_ptr Object::fetch(td::TlParser &p) { return db_root_key_config::fetch(p); case db_state_asyncSerializer::ID: return db_state_asyncSerializer::fetch(p); + case db_state_dbVersion::ID: + return db_state_dbVersion::fetch(p); case db_state_destroyedSessions::ID: return db_state_destroyedSessions::fetch(p); case db_state_gcBlockId::ID: @@ -262,6 +276,8 @@ object_ptr Object::fetch(td::TlParser &p) { return db_state_key_asyncSerializer::fetch(p); case db_state_key_hardforks::ID: return db_state_key_hardforks::fetch(p); + case db_state_key_dbVersion::ID: + return db_state_key_dbVersion::fetch(p); case db_state_shardClient::ID: return db_state_shardClient::fetch(p); case dht_key::ID: @@ -366,6 +382,18 @@ object_ptr Object::fetch(td::TlParser &p) { return fec_roundRobin::fetch(p); case fec_online::ID: return fec_online::fetch(p); + case http_header::ID: + return http_header::fetch(p); + case http_payloadPart::ID: + return http_payloadPart::fetch(p); + case http_response::ID: + return http_response::fetch(p); + case http_server_config::ID: + return http_server_config::fetch(p); + case http_server_dnsEntry::ID: + return http_server_dnsEntry::fetch(p); + case http_server_host::ID: + return http_server_host::fetch(p); case id_config_local::ID: return id_config_local::fetch(p); case liteclient_config_global::ID: @@ -442,6 +470,10 @@ object_ptr Object::fetch(td::TlParser &p) { return ton_blockId::fetch(p); case ton_blockIdApprove::ID: return ton_blockIdApprove::fetch(p); + case tonNode_archiveNotFound::ID: + return tonNode_archiveNotFound::fetch(p); + case tonNode_archiveInfo::ID: + return tonNode_archiveInfo::fetch(p); case tonNode_blockDescriptionEmpty::ID: return tonNode_blockDescriptionEmpty::fetch(p); case tonNode_blockDescription::ID: @@ -640,6 +672,10 @@ object_ptr Function::fetch(td::TlParser &p) { return engine_validator_sign::fetch(p); case getTestObject::ID: return getTestObject::fetch(p); + case http_getNextPayloadPart::ID: + return http_getNextPayloadPart::fetch(p); + case http_request::ID: + return http_request::fetch(p); case overlay_getBroadcast::ID: return overlay_getBroadcast::fetch(p); case overlay_getBroadcastList::ID: @@ -672,6 +708,10 @@ object_ptr Function::fetch(td::TlParser &p) { return tonNode_downloadPersistentStateSlice::fetch(p); case tonNode_downloadZeroState::ID: return tonNode_downloadZeroState::fetch(p); + case tonNode_getArchiveInfo::ID: + return tonNode_getArchiveInfo::fetch(p); + case tonNode_getArchiveSlice::ID: + return tonNode_getArchiveSlice::fetch(p); case tonNode_getCapabilities::ID: return tonNode_getCapabilities::fetch(p); case tonNode_getNextBlockDescription::ID: @@ -4352,9 +4392,10 @@ db_block_info::db_block_info() , lt_() , ts_() , state_() + , masterchain_ref_seqno_() {} -db_block_info::db_block_info(object_ptr &&id_, std::int32_t flags_, object_ptr &&prev_left_, object_ptr &&prev_right_, object_ptr &&next_left_, object_ptr &&next_right_, std::int64_t lt_, std::int32_t ts_, td::Bits256 const &state_) +db_block_info::db_block_info(object_ptr &&id_, std::int32_t flags_, object_ptr &&prev_left_, object_ptr &&prev_right_, object_ptr &&next_left_, object_ptr &&next_right_, std::int64_t lt_, std::int32_t ts_, td::Bits256 const &state_, std::int32_t masterchain_ref_seqno_) : id_(std::move(id_)) , flags_(flags_) , prev_left_(std::move(prev_left_)) @@ -4364,6 +4405,7 @@ db_block_info::db_block_info(object_ptr &&id_, std::int32_t , lt_(lt_) , ts_(ts_) , state_(state_) + , masterchain_ref_seqno_(masterchain_ref_seqno_) {} const std::int32_t db_block_info::ID; @@ -4381,6 +4423,7 @@ object_ptr db_block_info::fetch(td::TlParser &p) { if (var0 & 8192) { res->lt_ = TlFetchLong::parse(p); } if (var0 & 16384) { res->ts_ = TlFetchInt::parse(p); } if (var0 & 131072) { res->state_ = TlFetchInt256::parse(p); } + if (var0 & 8388608) { res->masterchain_ref_seqno_ = TlFetchInt::parse(p); } if (p.get_error()) { FAIL(""); } return std::move(res); #undef FAIL @@ -4398,6 +4441,7 @@ void db_block_info::store(td::TlStorerCalcLength &s) const { if (var0 & 8192) { TlStoreBinary::store(lt_, s); } if (var0 & 16384) { TlStoreBinary::store(ts_, s); } if (var0 & 131072) { TlStoreBinary::store(state_, s); } + if (var0 & 8388608) { TlStoreBinary::store(masterchain_ref_seqno_, s); } } void db_block_info::store(td::TlStorerUnsafe &s) const { @@ -4412,6 +4456,7 @@ void db_block_info::store(td::TlStorerUnsafe &s) const { if (var0 & 8192) { TlStoreBinary::store(lt_, s); } if (var0 & 16384) { TlStoreBinary::store(ts_, s); } if (var0 & 131072) { TlStoreBinary::store(state_, s); } + if (var0 & 8388608) { TlStoreBinary::store(masterchain_ref_seqno_, s); } } void db_block_info::store(td::TlStorerToString &s, const char *field_name) const { @@ -4427,6 +4472,7 @@ void db_block_info::store(td::TlStorerToString &s, const char *field_name) const if (var0 & 8192) { s.store_field("lt", lt_); } if (var0 & 16384) { s.store_field("ts", ts_); } if (var0 & 131072) { s.store_field("state", state_); } + if (var0 & 8388608) { s.store_field("masterchain_ref_seqno", masterchain_ref_seqno_); } s.store_class_end(); } } @@ -4882,6 +4928,8 @@ object_ptr db_filedb_Key::fetch(td::TlParser &p) { return db_filedb_key_signatures::fetch(p); case db_filedb_key_candidate::ID: return db_filedb_key_candidate::fetch(p); + case db_filedb_key_blockInfo::ID: + return db_filedb_key_blockInfo::fetch(p); default: FAIL(PSTRING() << "Unknown constructor found " << td::format::as_hex(constructor)); } @@ -5191,6 +5239,44 @@ void db_filedb_key_candidate::store(td::TlStorerToString &s, const char *field_n } } +db_filedb_key_blockInfo::db_filedb_key_blockInfo() + : block_id_() +{} + +db_filedb_key_blockInfo::db_filedb_key_blockInfo(object_ptr &&block_id_) + : block_id_(std::move(block_id_)) +{} + +const std::int32_t db_filedb_key_blockInfo::ID; + +object_ptr db_filedb_key_blockInfo::fetch(td::TlParser &p) { + return make_object(p); +} + +db_filedb_key_blockInfo::db_filedb_key_blockInfo(td::TlParser &p) +#define FAIL(error) p.set_error(error) + : block_id_(TlFetchObject::parse(p)) +#undef FAIL +{} + +void db_filedb_key_blockInfo::store(td::TlStorerCalcLength &s) const { + (void)sizeof(s); + TlStoreObject::store(block_id_, s); +} + +void db_filedb_key_blockInfo::store(td::TlStorerUnsafe &s) const { + (void)sizeof(s); + TlStoreObject::store(block_id_, s); +} + +void db_filedb_key_blockInfo::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "db_filedb_key_blockInfo"); + if (block_id_ == nullptr) { s.store_field("block_id", "null"); } else { block_id_->store(s, "block_id"); } + s.store_class_end(); + } +} + db_filedb_value::db_filedb_value() : key_() , prev_() @@ -5247,6 +5333,275 @@ void db_filedb_value::store(td::TlStorerToString &s, const char *field_name) con } } +object_ptr db_files_Key::fetch(td::TlParser &p) { +#define FAIL(error) p.set_error(error); return nullptr; + int constructor = p.fetch_int(); + switch (constructor) { + case db_files_index_key::ID: + return db_files_index_key::fetch(p); + case db_files_package_key::ID: + return db_files_package_key::fetch(p); + default: + FAIL(PSTRING() << "Unknown constructor found " << td::format::as_hex(constructor)); + } +#undef FAIL +} + +db_files_index_key::db_files_index_key() { +} + +const std::int32_t db_files_index_key::ID; + +object_ptr db_files_index_key::fetch(td::TlParser &p) { + return make_object(p); +} + +db_files_index_key::db_files_index_key(td::TlParser &p) +#define FAIL(error) p.set_error(error) +#undef FAIL +{ + (void)p; +} + +void db_files_index_key::store(td::TlStorerCalcLength &s) const { + (void)sizeof(s); +} + +void db_files_index_key::store(td::TlStorerUnsafe &s) const { + (void)sizeof(s); +} + +void db_files_index_key::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "db_files_index_key"); + s.store_class_end(); + } +} + +db_files_package_key::db_files_package_key() + : package_id_() + , key_() + , temp_() +{} + +db_files_package_key::db_files_package_key(std::int32_t package_id_, bool key_, bool temp_) + : package_id_(package_id_) + , key_(key_) + , temp_(temp_) +{} + +const std::int32_t db_files_package_key::ID; + +object_ptr db_files_package_key::fetch(td::TlParser &p) { + return make_object(p); +} + +db_files_package_key::db_files_package_key(td::TlParser &p) +#define FAIL(error) p.set_error(error) + : package_id_(TlFetchInt::parse(p)) + , key_(TlFetchBool::parse(p)) + , temp_(TlFetchBool::parse(p)) +#undef FAIL +{} + +void db_files_package_key::store(td::TlStorerCalcLength &s) const { + (void)sizeof(s); + TlStoreBinary::store(package_id_, s); + TlStoreBool::store(key_, s); + TlStoreBool::store(temp_, s); +} + +void db_files_package_key::store(td::TlStorerUnsafe &s) const { + (void)sizeof(s); + TlStoreBinary::store(package_id_, s); + TlStoreBool::store(key_, s); + TlStoreBool::store(temp_, s); +} + +void db_files_package_key::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "db_files_package_key"); + s.store_field("package_id", package_id_); + s.store_field("key", key_); + s.store_field("temp", temp_); + s.store_class_end(); + } +} + +db_files_index_value::db_files_index_value() + : packages_() + , key_packages_() + , temp_packages_() +{} + +db_files_index_value::db_files_index_value(std::vector &&packages_, std::vector &&key_packages_, std::vector &&temp_packages_) + : packages_(std::move(packages_)) + , key_packages_(std::move(key_packages_)) + , temp_packages_(std::move(temp_packages_)) +{} + +const std::int32_t db_files_index_value::ID; + +object_ptr db_files_index_value::fetch(td::TlParser &p) { + return make_object(p); +} + +db_files_index_value::db_files_index_value(td::TlParser &p) +#define FAIL(error) p.set_error(error) + : packages_(TlFetchVector::parse(p)) + , key_packages_(TlFetchVector::parse(p)) + , temp_packages_(TlFetchVector::parse(p)) +#undef FAIL +{} + +void db_files_index_value::store(td::TlStorerCalcLength &s) const { + (void)sizeof(s); + TlStoreVector::store(packages_, s); + TlStoreVector::store(key_packages_, s); + TlStoreVector::store(temp_packages_, s); +} + +void db_files_index_value::store(td::TlStorerUnsafe &s) const { + (void)sizeof(s); + TlStoreVector::store(packages_, s); + TlStoreVector::store(key_packages_, s); + TlStoreVector::store(temp_packages_, s); +} + +void db_files_index_value::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "db_files_index_value"); + { const std::vector &v = packages_; const std::uint32_t multiplicity = static_cast(v.size()); const auto vector_name = "vector[" + td::to_string(multiplicity)+ "]"; s.store_class_begin("packages", vector_name.c_str()); for (std::uint32_t i = 0; i < multiplicity; i++) { s.store_field("", v[i]); } s.store_class_end(); } + { const std::vector &v = key_packages_; const std::uint32_t multiplicity = static_cast(v.size()); const auto vector_name = "vector[" + td::to_string(multiplicity)+ "]"; s.store_class_begin("key_packages", vector_name.c_str()); for (std::uint32_t i = 0; i < multiplicity; i++) { s.store_field("", v[i]); } s.store_class_end(); } + { const std::vector &v = temp_packages_; const std::uint32_t multiplicity = static_cast(v.size()); const auto vector_name = "vector[" + td::to_string(multiplicity)+ "]"; s.store_class_begin("temp_packages", vector_name.c_str()); for (std::uint32_t i = 0; i < multiplicity; i++) { s.store_field("", v[i]); } s.store_class_end(); } + s.store_class_end(); + } +} + +db_files_package_firstBlock::db_files_package_firstBlock() + : workchain_() + , shard_() + , seqno_() + , unixtime_() + , lt_() +{} + +db_files_package_firstBlock::db_files_package_firstBlock(std::int32_t workchain_, std::int64_t shard_, std::int32_t seqno_, std::int32_t unixtime_, std::int64_t lt_) + : workchain_(workchain_) + , shard_(shard_) + , seqno_(seqno_) + , unixtime_(unixtime_) + , lt_(lt_) +{} + +const std::int32_t db_files_package_firstBlock::ID; + +object_ptr db_files_package_firstBlock::fetch(td::TlParser &p) { + return make_object(p); +} + +db_files_package_firstBlock::db_files_package_firstBlock(td::TlParser &p) +#define FAIL(error) p.set_error(error) + : workchain_(TlFetchInt::parse(p)) + , shard_(TlFetchLong::parse(p)) + , seqno_(TlFetchInt::parse(p)) + , unixtime_(TlFetchInt::parse(p)) + , lt_(TlFetchLong::parse(p)) +#undef FAIL +{} + +void db_files_package_firstBlock::store(td::TlStorerCalcLength &s) const { + (void)sizeof(s); + TlStoreBinary::store(workchain_, s); + TlStoreBinary::store(shard_, s); + TlStoreBinary::store(seqno_, s); + TlStoreBinary::store(unixtime_, s); + TlStoreBinary::store(lt_, s); +} + +void db_files_package_firstBlock::store(td::TlStorerUnsafe &s) const { + (void)sizeof(s); + TlStoreBinary::store(workchain_, s); + TlStoreBinary::store(shard_, s); + TlStoreBinary::store(seqno_, s); + TlStoreBinary::store(unixtime_, s); + TlStoreBinary::store(lt_, s); +} + +void db_files_package_firstBlock::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "db_files_package_firstBlock"); + s.store_field("workchain", workchain_); + s.store_field("shard", shard_); + s.store_field("seqno", seqno_); + s.store_field("unixtime", unixtime_); + s.store_field("lt", lt_); + s.store_class_end(); + } +} + +db_files_package_value::db_files_package_value() + : package_id_() + , key_() + , temp_() + , firstblocks_() + , deleted_() +{} + +db_files_package_value::db_files_package_value(std::int32_t package_id_, bool key_, bool temp_, std::vector> &&firstblocks_, bool deleted_) + : package_id_(package_id_) + , key_(key_) + , temp_(temp_) + , firstblocks_(std::move(firstblocks_)) + , deleted_(deleted_) +{} + +const std::int32_t db_files_package_value::ID; + +object_ptr db_files_package_value::fetch(td::TlParser &p) { + return make_object(p); +} + +db_files_package_value::db_files_package_value(td::TlParser &p) +#define FAIL(error) p.set_error(error) + : package_id_(TlFetchInt::parse(p)) + , key_(TlFetchBool::parse(p)) + , temp_(TlFetchBool::parse(p)) + , firstblocks_(TlFetchVector>::parse(p)) + , deleted_(TlFetchBool::parse(p)) +#undef FAIL +{} + +void db_files_package_value::store(td::TlStorerCalcLength &s) const { + (void)sizeof(s); + TlStoreBinary::store(package_id_, s); + TlStoreBool::store(key_, s); + TlStoreBool::store(temp_, s); + TlStoreVector::store(firstblocks_, s); + TlStoreBool::store(deleted_, s); +} + +void db_files_package_value::store(td::TlStorerUnsafe &s) const { + (void)sizeof(s); + TlStoreBinary::store(package_id_, s); + TlStoreBool::store(key_, s); + TlStoreBool::store(temp_, s); + TlStoreVector::store(firstblocks_, s); + TlStoreBool::store(deleted_, s); +} + +void db_files_package_value::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "db_files_package_value"); + s.store_field("package_id", package_id_); + s.store_field("key", key_); + s.store_field("temp", temp_); + { const std::vector> &v = firstblocks_; const std::uint32_t multiplicity = static_cast(v.size()); const auto vector_name = "vector[" + td::to_string(multiplicity)+ "]"; s.store_class_begin("firstblocks", vector_name.c_str()); for (std::uint32_t i = 0; i < multiplicity; i++) { if (v[i] == nullptr) { s.store_field("", "null"); } else { v[i]->store(s, ""); } } s.store_class_end(); } + s.store_field("deleted", deleted_); + s.store_class_end(); + } +} + object_ptr db_lt_Key::fetch(td::TlParser &p) { #define FAIL(error) p.set_error(error); return nullptr; int constructor = p.fetch_int(); @@ -5889,6 +6244,44 @@ void db_state_asyncSerializer::store(td::TlStorerToString &s, const char *field_ } } +db_state_dbVersion::db_state_dbVersion() + : version_() +{} + +db_state_dbVersion::db_state_dbVersion(std::int32_t version_) + : version_(version_) +{} + +const std::int32_t db_state_dbVersion::ID; + +object_ptr db_state_dbVersion::fetch(td::TlParser &p) { + return make_object(p); +} + +db_state_dbVersion::db_state_dbVersion(td::TlParser &p) +#define FAIL(error) p.set_error(error) + : version_(TlFetchInt::parse(p)) +#undef FAIL +{} + +void db_state_dbVersion::store(td::TlStorerCalcLength &s) const { + (void)sizeof(s); + TlStoreBinary::store(version_, s); +} + +void db_state_dbVersion::store(td::TlStorerUnsafe &s) const { + (void)sizeof(s); + TlStoreBinary::store(version_, s); +} + +void db_state_dbVersion::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "db_state_dbVersion"); + s.store_field("version", version_); + s.store_class_end(); + } +} + db_state_destroyedSessions::db_state_destroyedSessions() : sessions_() {} @@ -6057,6 +6450,8 @@ object_ptr db_state_Key::fetch(td::TlParser &p) { return db_state_key_asyncSerializer::fetch(p); case db_state_key_hardforks::ID: return db_state_key_hardforks::fetch(p); + case db_state_key_dbVersion::ID: + return db_state_key_dbVersion::fetch(p); default: FAIL(PSTRING() << "Unknown constructor found " << td::format::as_hex(constructor)); } @@ -6249,6 +6644,37 @@ void db_state_key_hardforks::store(td::TlStorerToString &s, const char *field_na } } +db_state_key_dbVersion::db_state_key_dbVersion() { +} + +const std::int32_t db_state_key_dbVersion::ID; + +object_ptr db_state_key_dbVersion::fetch(td::TlParser &p) { + return make_object(p); +} + +db_state_key_dbVersion::db_state_key_dbVersion(td::TlParser &p) +#define FAIL(error) p.set_error(error) +#undef FAIL +{ + (void)p; +} + +void db_state_key_dbVersion::store(td::TlStorerCalcLength &s) const { + (void)sizeof(s); +} + +void db_state_key_dbVersion::store(td::TlStorerUnsafe &s) const { + (void)sizeof(s); +} + +void db_state_key_dbVersion::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "db_state_key_dbVersion"); + s.store_class_end(); + } +} + db_state_shardClient::db_state_shardClient() : block_() {} @@ -8654,6 +9080,300 @@ void fec_online::store(td::TlStorerToString &s, const char *field_name) const { } } +http_header::http_header() + : name_() + , value_() +{} + +http_header::http_header(std::string const &name_, std::string const &value_) + : name_(std::move(name_)) + , value_(std::move(value_)) +{} + +const std::int32_t http_header::ID; + +object_ptr http_header::fetch(td::TlParser &p) { + return make_object(p); +} + +http_header::http_header(td::TlParser &p) +#define FAIL(error) p.set_error(error) + : name_(TlFetchString::parse(p)) + , value_(TlFetchString::parse(p)) +#undef FAIL +{} + +void http_header::store(td::TlStorerCalcLength &s) const { + (void)sizeof(s); + TlStoreString::store(name_, s); + TlStoreString::store(value_, s); +} + +void http_header::store(td::TlStorerUnsafe &s) const { + (void)sizeof(s); + TlStoreString::store(name_, s); + TlStoreString::store(value_, s); +} + +void http_header::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "http_header"); + s.store_field("name", name_); + s.store_field("value", value_); + s.store_class_end(); + } +} + +http_payloadPart::http_payloadPart() + : data_() + , trailer_() + , last_() +{} + +http_payloadPart::http_payloadPart(td::BufferSlice &&data_, std::vector> &&trailer_, bool last_) + : data_(std::move(data_)) + , trailer_(std::move(trailer_)) + , last_(last_) +{} + +const std::int32_t http_payloadPart::ID; + +object_ptr http_payloadPart::fetch(td::TlParser &p) { + return make_object(p); +} + +http_payloadPart::http_payloadPart(td::TlParser &p) +#define FAIL(error) p.set_error(error) + : data_(TlFetchBytes::parse(p)) + , trailer_(TlFetchVector>::parse(p)) + , last_(TlFetchBool::parse(p)) +#undef FAIL +{} + +void http_payloadPart::store(td::TlStorerCalcLength &s) const { + (void)sizeof(s); + TlStoreString::store(data_, s); + TlStoreVector::store(trailer_, s); + TlStoreBool::store(last_, s); +} + +void http_payloadPart::store(td::TlStorerUnsafe &s) const { + (void)sizeof(s); + TlStoreString::store(data_, s); + TlStoreVector::store(trailer_, s); + TlStoreBool::store(last_, s); +} + +void http_payloadPart::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "http_payloadPart"); + s.store_bytes_field("data", data_); + { const std::vector> &v = trailer_; const std::uint32_t multiplicity = static_cast(v.size()); const auto vector_name = "vector[" + td::to_string(multiplicity)+ "]"; s.store_class_begin("trailer", vector_name.c_str()); for (std::uint32_t i = 0; i < multiplicity; i++) { if (v[i] == nullptr) { s.store_field("", "null"); } else { v[i]->store(s, ""); } } s.store_class_end(); } + s.store_field("last", last_); + s.store_class_end(); + } +} + +http_response::http_response() + : http_version_() + , status_code_() + , reason_() + , headers_() +{} + +http_response::http_response(std::string const &http_version_, std::int32_t status_code_, std::string const &reason_, std::vector> &&headers_) + : http_version_(std::move(http_version_)) + , status_code_(status_code_) + , reason_(std::move(reason_)) + , headers_(std::move(headers_)) +{} + +const std::int32_t http_response::ID; + +object_ptr http_response::fetch(td::TlParser &p) { + return make_object(p); +} + +http_response::http_response(td::TlParser &p) +#define FAIL(error) p.set_error(error) + : http_version_(TlFetchString::parse(p)) + , status_code_(TlFetchInt::parse(p)) + , reason_(TlFetchString::parse(p)) + , headers_(TlFetchVector>::parse(p)) +#undef FAIL +{} + +void http_response::store(td::TlStorerCalcLength &s) const { + (void)sizeof(s); + TlStoreString::store(http_version_, s); + TlStoreBinary::store(status_code_, s); + TlStoreString::store(reason_, s); + TlStoreVector::store(headers_, s); +} + +void http_response::store(td::TlStorerUnsafe &s) const { + (void)sizeof(s); + TlStoreString::store(http_version_, s); + TlStoreBinary::store(status_code_, s); + TlStoreString::store(reason_, s); + TlStoreVector::store(headers_, s); +} + +void http_response::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "http_response"); + s.store_field("http_version", http_version_); + s.store_field("status_code", status_code_); + s.store_field("reason", reason_); + { const std::vector> &v = headers_; const std::uint32_t multiplicity = static_cast(v.size()); const auto vector_name = "vector[" + td::to_string(multiplicity)+ "]"; s.store_class_begin("headers", vector_name.c_str()); for (std::uint32_t i = 0; i < multiplicity; i++) { if (v[i] == nullptr) { s.store_field("", "null"); } else { v[i]->store(s, ""); } } s.store_class_end(); } + s.store_class_end(); + } +} + +http_server_config::http_server_config() + : dhs_() + , local_hosts_() +{} + +http_server_config::http_server_config(std::vector> &&dhs_, std::vector> &&local_hosts_) + : dhs_(std::move(dhs_)) + , local_hosts_(std::move(local_hosts_)) +{} + +const std::int32_t http_server_config::ID; + +object_ptr http_server_config::fetch(td::TlParser &p) { + return make_object(p); +} + +http_server_config::http_server_config(td::TlParser &p) +#define FAIL(error) p.set_error(error) + : dhs_(TlFetchVector>::parse(p)) + , local_hosts_(TlFetchVector>::parse(p)) +#undef FAIL +{} + +void http_server_config::store(td::TlStorerCalcLength &s) const { + (void)sizeof(s); + TlStoreVector::store(dhs_, s); + TlStoreVector::store(local_hosts_, s); +} + +void http_server_config::store(td::TlStorerUnsafe &s) const { + (void)sizeof(s); + TlStoreVector::store(dhs_, s); + TlStoreVector::store(local_hosts_, s); +} + +void http_server_config::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "http_server_config"); + { const std::vector> &v = dhs_; const std::uint32_t multiplicity = static_cast(v.size()); const auto vector_name = "vector[" + td::to_string(multiplicity)+ "]"; s.store_class_begin("dhs", vector_name.c_str()); for (std::uint32_t i = 0; i < multiplicity; i++) { if (v[i] == nullptr) { s.store_field("", "null"); } else { v[i]->store(s, ""); } } s.store_class_end(); } + { const std::vector> &v = local_hosts_; const std::uint32_t multiplicity = static_cast(v.size()); const auto vector_name = "vector[" + td::to_string(multiplicity)+ "]"; s.store_class_begin("local_hosts", vector_name.c_str()); for (std::uint32_t i = 0; i < multiplicity; i++) { if (v[i] == nullptr) { s.store_field("", "null"); } else { v[i]->store(s, ""); } } s.store_class_end(); } + s.store_class_end(); + } +} + +http_server_dnsEntry::http_server_dnsEntry() + : domain_() + , addr_() +{} + +http_server_dnsEntry::http_server_dnsEntry(std::string const &domain_, object_ptr &&addr_) + : domain_(std::move(domain_)) + , addr_(std::move(addr_)) +{} + +const std::int32_t http_server_dnsEntry::ID; + +object_ptr http_server_dnsEntry::fetch(td::TlParser &p) { + return make_object(p); +} + +http_server_dnsEntry::http_server_dnsEntry(td::TlParser &p) +#define FAIL(error) p.set_error(error) + : domain_(TlFetchString::parse(p)) + , addr_(TlFetchObject::parse(p)) +#undef FAIL +{} + +void http_server_dnsEntry::store(td::TlStorerCalcLength &s) const { + (void)sizeof(s); + TlStoreString::store(domain_, s); + TlStoreObject::store(addr_, s); +} + +void http_server_dnsEntry::store(td::TlStorerUnsafe &s) const { + (void)sizeof(s); + TlStoreString::store(domain_, s); + TlStoreObject::store(addr_, s); +} + +void http_server_dnsEntry::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "http_server_dnsEntry"); + s.store_field("domain", domain_); + if (addr_ == nullptr) { s.store_field("addr", "null"); } else { addr_->store(s, "addr"); } + s.store_class_end(); + } +} + +http_server_host::http_server_host() + : domains_() + , ip_() + , port_() + , adnl_id_() +{} + +http_server_host::http_server_host(std::vector &&domains_, std::int32_t ip_, std::int32_t port_, object_ptr &&adnl_id_) + : domains_(std::move(domains_)) + , ip_(ip_) + , port_(port_) + , adnl_id_(std::move(adnl_id_)) +{} + +const std::int32_t http_server_host::ID; + +object_ptr http_server_host::fetch(td::TlParser &p) { + return make_object(p); +} + +http_server_host::http_server_host(td::TlParser &p) +#define FAIL(error) p.set_error(error) + : domains_(TlFetchVector>::parse(p)) + , ip_(TlFetchInt::parse(p)) + , port_(TlFetchInt::parse(p)) + , adnl_id_(TlFetchObject::parse(p)) +#undef FAIL +{} + +void http_server_host::store(td::TlStorerCalcLength &s) const { + (void)sizeof(s); + TlStoreVector::store(domains_, s); + TlStoreBinary::store(ip_, s); + TlStoreBinary::store(port_, s); + TlStoreObject::store(adnl_id_, s); +} + +void http_server_host::store(td::TlStorerUnsafe &s) const { + (void)sizeof(s); + TlStoreVector::store(domains_, s); + TlStoreBinary::store(ip_, s); + TlStoreBinary::store(port_, s); + TlStoreObject::store(adnl_id_, s); +} + +void http_server_host::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "http_server_host"); + { const std::vector &v = domains_; const std::uint32_t multiplicity = static_cast(v.size()); const auto vector_name = "vector[" + td::to_string(multiplicity)+ "]"; s.store_class_begin("domains", vector_name.c_str()); for (std::uint32_t i = 0; i < multiplicity; i++) { s.store_field("", v[i]); } s.store_class_end(); } + s.store_field("ip", ip_); + s.store_field("port", port_); + if (adnl_id_ == nullptr) { s.store_field("adnl_id", "null"); } else { adnl_id_->store(s, "adnl_id"); } + s.store_class_end(); + } +} + id_config_local::id_config_local() : id_() {} @@ -10558,6 +11278,89 @@ void ton_blockIdApprove::store(td::TlStorerToString &s, const char *field_name) } } +object_ptr tonNode_ArchiveInfo::fetch(td::TlParser &p) { +#define FAIL(error) p.set_error(error); return nullptr; + int constructor = p.fetch_int(); + switch (constructor) { + case tonNode_archiveNotFound::ID: + return tonNode_archiveNotFound::fetch(p); + case tonNode_archiveInfo::ID: + return tonNode_archiveInfo::fetch(p); + default: + FAIL(PSTRING() << "Unknown constructor found " << td::format::as_hex(constructor)); + } +#undef FAIL +} + +tonNode_archiveNotFound::tonNode_archiveNotFound() { +} + +const std::int32_t tonNode_archiveNotFound::ID; + +object_ptr tonNode_archiveNotFound::fetch(td::TlParser &p) { + return make_object(p); +} + +tonNode_archiveNotFound::tonNode_archiveNotFound(td::TlParser &p) +#define FAIL(error) p.set_error(error) +#undef FAIL +{ + (void)p; +} + +void tonNode_archiveNotFound::store(td::TlStorerCalcLength &s) const { + (void)sizeof(s); +} + +void tonNode_archiveNotFound::store(td::TlStorerUnsafe &s) const { + (void)sizeof(s); +} + +void tonNode_archiveNotFound::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "tonNode_archiveNotFound"); + s.store_class_end(); + } +} + +tonNode_archiveInfo::tonNode_archiveInfo() + : id_() +{} + +tonNode_archiveInfo::tonNode_archiveInfo(std::int64_t id_) + : id_(id_) +{} + +const std::int32_t tonNode_archiveInfo::ID; + +object_ptr tonNode_archiveInfo::fetch(td::TlParser &p) { + return make_object(p); +} + +tonNode_archiveInfo::tonNode_archiveInfo(td::TlParser &p) +#define FAIL(error) p.set_error(error) + : id_(TlFetchLong::parse(p)) +#undef FAIL +{} + +void tonNode_archiveInfo::store(td::TlStorerCalcLength &s) const { + (void)sizeof(s); + TlStoreBinary::store(id_, s); +} + +void tonNode_archiveInfo::store(td::TlStorerUnsafe &s) const { + (void)sizeof(s); + TlStoreBinary::store(id_, s); +} + +void tonNode_archiveInfo::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "tonNode_archiveInfo"); + s.store_field("id", id_); + s.store_class_end(); + } +} + object_ptr tonNode_BlockDescription::fetch(td::TlParser &p) { #define FAIL(error) p.set_error(error); return nullptr; int constructor = p.fetch_int(); @@ -15164,6 +15967,134 @@ getTestObject::ReturnType getTestObject::fetch_result(td::TlParser &p) { #undef FAIL } +http_getNextPayloadPart::http_getNextPayloadPart() + : id_() + , seqno_() + , max_chunk_size_() +{} + +http_getNextPayloadPart::http_getNextPayloadPart(td::Bits256 const &id_, std::int32_t seqno_, std::int32_t max_chunk_size_) + : id_(id_) + , seqno_(seqno_) + , max_chunk_size_(max_chunk_size_) +{} + +const std::int32_t http_getNextPayloadPart::ID; + +object_ptr http_getNextPayloadPart::fetch(td::TlParser &p) { + return make_object(p); +} + +http_getNextPayloadPart::http_getNextPayloadPart(td::TlParser &p) +#define FAIL(error) p.set_error(error) + : id_(TlFetchInt256::parse(p)) + , seqno_(TlFetchInt::parse(p)) + , max_chunk_size_(TlFetchInt::parse(p)) +#undef FAIL +{} + +void http_getNextPayloadPart::store(td::TlStorerCalcLength &s) const { + (void)sizeof(s); + s.store_binary(-1871422196); + TlStoreBinary::store(id_, s); + TlStoreBinary::store(seqno_, s); + TlStoreBinary::store(max_chunk_size_, s); +} + +void http_getNextPayloadPart::store(td::TlStorerUnsafe &s) const { + (void)sizeof(s); + s.store_binary(-1871422196); + TlStoreBinary::store(id_, s); + TlStoreBinary::store(seqno_, s); + TlStoreBinary::store(max_chunk_size_, s); +} + +void http_getNextPayloadPart::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "http_getNextPayloadPart"); + s.store_field("id", id_); + s.store_field("seqno", seqno_); + s.store_field("max_chunk_size", max_chunk_size_); + s.store_class_end(); + } +} + +http_getNextPayloadPart::ReturnType http_getNextPayloadPart::fetch_result(td::TlParser &p) { +#define FAIL(error) p.set_error(error); return ReturnType() + return TlFetchBoxed, 693819236>::parse(p); +#undef FAIL +} + +http_request::http_request() + : id_() + , method_() + , url_() + , http_version_() + , headers_() +{} + +http_request::http_request(td::Bits256 const &id_, std::string const &method_, std::string const &url_, std::string const &http_version_, std::vector> &&headers_) + : id_(id_) + , method_(std::move(method_)) + , url_(std::move(url_)) + , http_version_(std::move(http_version_)) + , headers_(std::move(headers_)) +{} + +const std::int32_t http_request::ID; + +object_ptr http_request::fetch(td::TlParser &p) { + return make_object(p); +} + +http_request::http_request(td::TlParser &p) +#define FAIL(error) p.set_error(error) + : id_(TlFetchInt256::parse(p)) + , method_(TlFetchString::parse(p)) + , url_(TlFetchString::parse(p)) + , http_version_(TlFetchString::parse(p)) + , headers_(TlFetchVector>::parse(p)) +#undef FAIL +{} + +void http_request::store(td::TlStorerCalcLength &s) const { + (void)sizeof(s); + s.store_binary(1639027169); + TlStoreBinary::store(id_, s); + TlStoreString::store(method_, s); + TlStoreString::store(url_, s); + TlStoreString::store(http_version_, s); + TlStoreVector::store(headers_, s); +} + +void http_request::store(td::TlStorerUnsafe &s) const { + (void)sizeof(s); + s.store_binary(1639027169); + TlStoreBinary::store(id_, s); + TlStoreString::store(method_, s); + TlStoreString::store(url_, s); + TlStoreString::store(http_version_, s); + TlStoreVector::store(headers_, s); +} + +void http_request::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "http_request"); + s.store_field("id", id_); + s.store_field("method", method_); + s.store_field("url", url_); + s.store_field("http_version", http_version_); + { const std::vector> &v = headers_; const std::uint32_t multiplicity = static_cast(v.size()); const auto vector_name = "vector[" + td::to_string(multiplicity)+ "]"; s.store_class_begin("headers", vector_name.c_str()); for (std::uint32_t i = 0; i < multiplicity; i++) { if (v[i] == nullptr) { s.store_field("", "null"); } else { v[i]->store(s, ""); } } s.store_class_end(); } + s.store_class_end(); + } +} + +http_request::ReturnType http_request::fetch_result(td::TlParser &p) { +#define FAIL(error) p.set_error(error); return ReturnType() + return TlFetchBoxed, -273307789>::parse(p); +#undef FAIL +} + overlay_getBroadcast::overlay_getBroadcast() : hash_() {} @@ -15924,6 +16855,110 @@ tonNode_downloadZeroState::ReturnType tonNode_downloadZeroState::fetch_result(td #undef FAIL } +tonNode_getArchiveInfo::tonNode_getArchiveInfo() + : masterchain_seqno_() +{} + +tonNode_getArchiveInfo::tonNode_getArchiveInfo(std::int32_t masterchain_seqno_) + : masterchain_seqno_(masterchain_seqno_) +{} + +const std::int32_t tonNode_getArchiveInfo::ID; + +object_ptr tonNode_getArchiveInfo::fetch(td::TlParser &p) { + return make_object(p); +} + +tonNode_getArchiveInfo::tonNode_getArchiveInfo(td::TlParser &p) +#define FAIL(error) p.set_error(error) + : masterchain_seqno_(TlFetchInt::parse(p)) +#undef FAIL +{} + +void tonNode_getArchiveInfo::store(td::TlStorerCalcLength &s) const { + (void)sizeof(s); + s.store_binary(2066602305); + TlStoreBinary::store(masterchain_seqno_, s); +} + +void tonNode_getArchiveInfo::store(td::TlStorerUnsafe &s) const { + (void)sizeof(s); + s.store_binary(2066602305); + TlStoreBinary::store(masterchain_seqno_, s); +} + +void tonNode_getArchiveInfo::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "tonNode_getArchiveInfo"); + s.store_field("masterchain_seqno", masterchain_seqno_); + s.store_class_end(); + } +} + +tonNode_getArchiveInfo::ReturnType tonNode_getArchiveInfo::fetch_result(td::TlParser &p) { +#define FAIL(error) p.set_error(error); return ReturnType() + return TlFetchObject::parse(p); +#undef FAIL +} + +tonNode_getArchiveSlice::tonNode_getArchiveSlice() + : archive_id_() + , offset_() + , max_size_() +{} + +tonNode_getArchiveSlice::tonNode_getArchiveSlice(std::int64_t archive_id_, std::int64_t offset_, std::int32_t max_size_) + : archive_id_(archive_id_) + , offset_(offset_) + , max_size_(max_size_) +{} + +const std::int32_t tonNode_getArchiveSlice::ID; + +object_ptr tonNode_getArchiveSlice::fetch(td::TlParser &p) { + return make_object(p); +} + +tonNode_getArchiveSlice::tonNode_getArchiveSlice(td::TlParser &p) +#define FAIL(error) p.set_error(error) + : archive_id_(TlFetchLong::parse(p)) + , offset_(TlFetchLong::parse(p)) + , max_size_(TlFetchInt::parse(p)) +#undef FAIL +{} + +void tonNode_getArchiveSlice::store(td::TlStorerCalcLength &s) const { + (void)sizeof(s); + s.store_binary(540758376); + TlStoreBinary::store(archive_id_, s); + TlStoreBinary::store(offset_, s); + TlStoreBinary::store(max_size_, s); +} + +void tonNode_getArchiveSlice::store(td::TlStorerUnsafe &s) const { + (void)sizeof(s); + s.store_binary(540758376); + TlStoreBinary::store(archive_id_, s); + TlStoreBinary::store(offset_, s); + TlStoreBinary::store(max_size_, s); +} + +void tonNode_getArchiveSlice::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "tonNode_getArchiveSlice"); + s.store_field("archive_id", archive_id_); + s.store_field("offset", offset_); + s.store_field("max_size", max_size_); + s.store_class_end(); + } +} + +tonNode_getArchiveSlice::ReturnType tonNode_getArchiveSlice::fetch_result(td::TlParser &p) { +#define FAIL(error) p.set_error(error); return ReturnType() + return TlFetchBoxed, 1443505284>::parse(p); +#undef FAIL +} + tonNode_getCapabilities::tonNode_getCapabilities() { } diff --git a/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api.h b/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api.h index 8bf7d8ff9b..6187d3f427 100644 --- a/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api.h +++ b/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api.h @@ -140,6 +140,14 @@ class db_filedb_Key; class db_filedb_value; +class db_files_Key; + +class db_files_index_value; + +class db_files_package_firstBlock; + +class db_files_package_value; + class db_lt_Key; class db_lt_desc_value; @@ -158,6 +166,8 @@ class db_root_Key; class db_state_asyncSerializer; +class db_state_dbVersion; + class db_state_destroyedSessions; class db_state_gcBlockId; @@ -258,6 +268,18 @@ class engine_validator_time; class fec_Type; +class http_header; + +class http_payloadPart; + +class http_response; + +class http_server_config; + +class http_server_dnsEntry; + +class http_server_host; + class id_config_local; class liteclient_config_global; @@ -304,6 +326,8 @@ class tcp_pong; class ton_BlockId; +class tonNode_ArchiveInfo; + class tonNode_BlockDescription; class tonNode_blockId; @@ -2362,11 +2386,12 @@ class db_block_info final : public db_block_Info { std::int64_t lt_; std::int32_t ts_; td::Bits256 state_; - enum Flags : std::int32_t {PREV_LEFT_MASK = 2, PREV_RIGHT_MASK = 4, NEXT_LEFT_MASK = 8, NEXT_RIGHT_MASK = 16, LT_MASK = 8192, TS_MASK = 16384, STATE_MASK = 131072}; + std::int32_t masterchain_ref_seqno_; + enum Flags : std::int32_t {PREV_LEFT_MASK = 2, PREV_RIGHT_MASK = 4, NEXT_LEFT_MASK = 8, NEXT_RIGHT_MASK = 16, LT_MASK = 8192, TS_MASK = 16384, STATE_MASK = 131072, MASTERCHAIN_REF_SEQNO_MASK = 8388608}; db_block_info(); - db_block_info(object_ptr &&id_, std::int32_t flags_, object_ptr &&prev_left_, object_ptr &&prev_right_, object_ptr &&next_left_, object_ptr &&next_right_, std::int64_t lt_, std::int32_t ts_, td::Bits256 const &state_); + db_block_info(object_ptr &&id_, std::int32_t flags_, object_ptr &&prev_left_, object_ptr &&prev_right_, object_ptr &&next_left_, object_ptr &&next_right_, std::int64_t lt_, std::int32_t ts_, td::Bits256 const &state_, std::int32_t masterchain_ref_seqno_); static const std::int32_t ID = 1254549287; std::int32_t get_id() const final { @@ -2811,6 +2836,30 @@ class db_filedb_key_candidate final : public db_filedb_Key { void store(td::TlStorerToString &s, const char *field_name) const final; }; +class db_filedb_key_blockInfo final : public db_filedb_Key { + public: + object_ptr block_id_; + + db_filedb_key_blockInfo(); + + explicit db_filedb_key_blockInfo(object_ptr &&block_id_); + + static const std::int32_t ID = -996551428; + std::int32_t get_id() const final { + return ID; + } + + static object_ptr fetch(td::TlParser &p); + + explicit db_filedb_key_blockInfo(td::TlParser &p); + + void store(td::TlStorerCalcLength &s) const final; + + void store(td::TlStorerUnsafe &s) const final; + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + class db_filedb_value final : public Object { public: object_ptr key_; @@ -2838,6 +2887,141 @@ class db_filedb_value final : public Object { void store(td::TlStorerToString &s, const char *field_name) const final; }; +class db_files_Key: public Object { + public: + + static object_ptr fetch(td::TlParser &p); +}; + +class db_files_index_key final : public db_files_Key { + public: + + db_files_index_key(); + + static const std::int32_t ID = 2109998338; + std::int32_t get_id() const final { + return ID; + } + + static object_ptr fetch(td::TlParser &p); + + explicit db_files_index_key(td::TlParser &p); + + void store(td::TlStorerCalcLength &s) const final; + + void store(td::TlStorerUnsafe &s) const final; + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + +class db_files_package_key final : public db_files_Key { + public: + std::int32_t package_id_; + bool key_; + bool temp_; + + db_files_package_key(); + + db_files_package_key(std::int32_t package_id_, bool key_, bool temp_); + + static const std::int32_t ID = -1526463682; + std::int32_t get_id() const final { + return ID; + } + + static object_ptr fetch(td::TlParser &p); + + explicit db_files_package_key(td::TlParser &p); + + void store(td::TlStorerCalcLength &s) const final; + + void store(td::TlStorerUnsafe &s) const final; + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + +class db_files_index_value final : public Object { + public: + std::vector packages_; + std::vector key_packages_; + std::vector temp_packages_; + + db_files_index_value(); + + db_files_index_value(std::vector &&packages_, std::vector &&key_packages_, std::vector &&temp_packages_); + + static const std::int32_t ID = -1565402372; + std::int32_t get_id() const final { + return ID; + } + + static object_ptr fetch(td::TlParser &p); + + explicit db_files_index_value(td::TlParser &p); + + void store(td::TlStorerCalcLength &s) const final; + + void store(td::TlStorerUnsafe &s) const final; + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + +class db_files_package_firstBlock final : public Object { + public: + std::int32_t workchain_; + std::int64_t shard_; + std::int32_t seqno_; + std::int32_t unixtime_; + std::int64_t lt_; + + db_files_package_firstBlock(); + + db_files_package_firstBlock(std::int32_t workchain_, std::int64_t shard_, std::int32_t seqno_, std::int32_t unixtime_, std::int64_t lt_); + + static const std::int32_t ID = 1880254951; + std::int32_t get_id() const final { + return ID; + } + + static object_ptr fetch(td::TlParser &p); + + explicit db_files_package_firstBlock(td::TlParser &p); + + void store(td::TlStorerCalcLength &s) const final; + + void store(td::TlStorerUnsafe &s) const final; + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + +class db_files_package_value final : public Object { + public: + std::int32_t package_id_; + bool key_; + bool temp_; + std::vector> firstblocks_; + bool deleted_; + + db_files_package_value(); + + db_files_package_value(std::int32_t package_id_, bool key_, bool temp_, std::vector> &&firstblocks_, bool deleted_); + + static const std::int32_t ID = -464726741; + std::int32_t get_id() const final { + return ID; + } + + static object_ptr fetch(td::TlParser &p); + + explicit db_files_package_value(td::TlParser &p); + + void store(td::TlStorerCalcLength &s) const final; + + void store(td::TlStorerUnsafe &s) const final; + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + class db_lt_Key: public Object { public: @@ -3195,6 +3379,30 @@ class db_state_asyncSerializer final : public Object { void store(td::TlStorerToString &s, const char *field_name) const final; }; +class db_state_dbVersion final : public Object { + public: + std::int32_t version_; + + db_state_dbVersion(); + + explicit db_state_dbVersion(std::int32_t version_); + + static const std::int32_t ID = -650698505; + std::int32_t get_id() const final { + return ID; + } + + static object_ptr fetch(td::TlParser &p); + + explicit db_state_dbVersion(td::TlParser &p); + + void store(td::TlStorerCalcLength &s) const final; + + void store(td::TlStorerUnsafe &s) const final; + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + class db_state_destroyedSessions final : public Object { public: std::vector sessions_; @@ -3423,6 +3631,27 @@ class db_state_key_hardforks final : public db_state_Key { void store(td::TlStorerToString &s, const char *field_name) const final; }; +class db_state_key_dbVersion final : public db_state_Key { + public: + + db_state_key_dbVersion(); + + static const std::int32_t ID = 1917788500; + std::int32_t get_id() const final { + return ID; + } + + static object_ptr fetch(td::TlParser &p); + + explicit db_state_key_dbVersion(td::TlParser &p); + + void store(td::TlStorerCalcLength &s) const final; + + void store(td::TlStorerUnsafe &s) const final; + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + class db_state_shardClient final : public Object { public: object_ptr block_; @@ -4751,6 +4980,161 @@ class fec_online final : public fec_Type { void store(td::TlStorerToString &s, const char *field_name) const final; }; +class http_header final : public Object { + public: + std::string name_; + std::string value_; + + http_header(); + + http_header(std::string const &name_, std::string const &value_); + + static const std::int32_t ID = -1902385903; + std::int32_t get_id() const final { + return ID; + } + + static object_ptr fetch(td::TlParser &p); + + explicit http_header(td::TlParser &p); + + void store(td::TlStorerCalcLength &s) const final; + + void store(td::TlStorerUnsafe &s) const final; + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + +class http_payloadPart final : public Object { + public: + td::BufferSlice data_; + std::vector> trailer_; + bool last_; + + http_payloadPart(); + + http_payloadPart(td::BufferSlice &&data_, std::vector> &&trailer_, bool last_); + + static const std::int32_t ID = 693819236; + std::int32_t get_id() const final { + return ID; + } + + static object_ptr fetch(td::TlParser &p); + + explicit http_payloadPart(td::TlParser &p); + + void store(td::TlStorerCalcLength &s) const final; + + void store(td::TlStorerUnsafe &s) const final; + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + +class http_response final : public Object { + public: + std::string http_version_; + std::int32_t status_code_; + std::string reason_; + std::vector> headers_; + + http_response(); + + http_response(std::string const &http_version_, std::int32_t status_code_, std::string const &reason_, std::vector> &&headers_); + + static const std::int32_t ID = -273307789; + std::int32_t get_id() const final { + return ID; + } + + static object_ptr fetch(td::TlParser &p); + + explicit http_response(td::TlParser &p); + + void store(td::TlStorerCalcLength &s) const final; + + void store(td::TlStorerUnsafe &s) const final; + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + +class http_server_config final : public Object { + public: + std::vector> dhs_; + std::vector> local_hosts_; + + http_server_config(); + + http_server_config(std::vector> &&dhs_, std::vector> &&local_hosts_); + + static const std::int32_t ID = 974419964; + std::int32_t get_id() const final { + return ID; + } + + static object_ptr fetch(td::TlParser &p); + + explicit http_server_config(td::TlParser &p); + + void store(td::TlStorerCalcLength &s) const final; + + void store(td::TlStorerUnsafe &s) const final; + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + +class http_server_dnsEntry final : public Object { + public: + std::string domain_; + object_ptr addr_; + + http_server_dnsEntry(); + + http_server_dnsEntry(std::string const &domain_, object_ptr &&addr_); + + static const std::int32_t ID = -663592810; + std::int32_t get_id() const final { + return ID; + } + + static object_ptr fetch(td::TlParser &p); + + explicit http_server_dnsEntry(td::TlParser &p); + + void store(td::TlStorerCalcLength &s) const final; + + void store(td::TlStorerUnsafe &s) const final; + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + +class http_server_host final : public Object { + public: + std::vector domains_; + std::int32_t ip_; + std::int32_t port_; + object_ptr adnl_id_; + + http_server_host(); + + http_server_host(std::vector &&domains_, std::int32_t ip_, std::int32_t port_, object_ptr &&adnl_id_); + + static const std::int32_t ID = -981605721; + std::int32_t get_id() const final { + return ID; + } + + static object_ptr fetch(td::TlParser &p); + + explicit http_server_host(td::TlParser &p); + + void store(td::TlStorerCalcLength &s) const final; + + void store(td::TlStorerUnsafe &s) const final; + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + class id_config_local final : public Object { public: object_ptr id_; @@ -5759,6 +6143,57 @@ class ton_blockIdApprove final : public ton_BlockId { void store(td::TlStorerToString &s, const char *field_name) const final; }; +class tonNode_ArchiveInfo: public Object { + public: + + static object_ptr fetch(td::TlParser &p); +}; + +class tonNode_archiveNotFound final : public tonNode_ArchiveInfo { + public: + + tonNode_archiveNotFound(); + + static const std::int32_t ID = -1725360509; + std::int32_t get_id() const final { + return ID; + } + + static object_ptr fetch(td::TlParser &p); + + explicit tonNode_archiveNotFound(td::TlParser &p); + + void store(td::TlStorerCalcLength &s) const final; + + void store(td::TlStorerUnsafe &s) const final; + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + +class tonNode_archiveInfo final : public tonNode_ArchiveInfo { + public: + std::int64_t id_; + + tonNode_archiveInfo(); + + explicit tonNode_archiveInfo(std::int64_t id_); + + static const std::int32_t ID = 435158924; + std::int32_t get_id() const final { + return ID; + } + + static object_ptr fetch(td::TlParser &p); + + explicit tonNode_archiveInfo(td::TlParser &p); + + void store(td::TlStorerCalcLength &s) const final; + + void store(td::TlStorerUnsafe &s) const final; + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + class tonNode_BlockDescription: public Object { public: @@ -8300,6 +8735,68 @@ class getTestObject final : public Function { static ReturnType fetch_result(td::TlParser &p); }; +class http_getNextPayloadPart final : public Function { + public: + td::Bits256 id_; + std::int32_t seqno_; + std::int32_t max_chunk_size_; + + http_getNextPayloadPart(); + + http_getNextPayloadPart(td::Bits256 const &id_, std::int32_t seqno_, std::int32_t max_chunk_size_); + + static const std::int32_t ID = -1871422196; + std::int32_t get_id() const final { + return ID; + } + + using ReturnType = object_ptr; + + static object_ptr fetch(td::TlParser &p); + + explicit http_getNextPayloadPart(td::TlParser &p); + + void store(td::TlStorerCalcLength &s) const final; + + void store(td::TlStorerUnsafe &s) const final; + + void store(td::TlStorerToString &s, const char *field_name) const final; + + static ReturnType fetch_result(td::TlParser &p); +}; + +class http_request final : public Function { + public: + td::Bits256 id_; + std::string method_; + std::string url_; + std::string http_version_; + std::vector> headers_; + + http_request(); + + http_request(td::Bits256 const &id_, std::string const &method_, std::string const &url_, std::string const &http_version_, std::vector> &&headers_); + + static const std::int32_t ID = 1639027169; + std::int32_t get_id() const final { + return ID; + } + + using ReturnType = object_ptr; + + static object_ptr fetch(td::TlParser &p); + + explicit http_request(td::TlParser &p); + + void store(td::TlStorerCalcLength &s) const final; + + void store(td::TlStorerUnsafe &s) const final; + + void store(td::TlStorerToString &s, const char *field_name) const final; + + static ReturnType fetch_result(td::TlParser &p); +}; + class overlay_getBroadcast final : public Function { public: td::Bits256 hash_; @@ -8752,6 +9249,64 @@ class tonNode_downloadZeroState final : public Function { static ReturnType fetch_result(td::TlParser &p); }; +class tonNode_getArchiveInfo final : public Function { + public: + std::int32_t masterchain_seqno_; + + tonNode_getArchiveInfo(); + + explicit tonNode_getArchiveInfo(std::int32_t masterchain_seqno_); + + static const std::int32_t ID = 2066602305; + std::int32_t get_id() const final { + return ID; + } + + using ReturnType = object_ptr; + + static object_ptr fetch(td::TlParser &p); + + explicit tonNode_getArchiveInfo(td::TlParser &p); + + void store(td::TlStorerCalcLength &s) const final; + + void store(td::TlStorerUnsafe &s) const final; + + void store(td::TlStorerToString &s, const char *field_name) const final; + + static ReturnType fetch_result(td::TlParser &p); +}; + +class tonNode_getArchiveSlice final : public Function { + public: + std::int64_t archive_id_; + std::int64_t offset_; + std::int32_t max_size_; + + tonNode_getArchiveSlice(); + + tonNode_getArchiveSlice(std::int64_t archive_id_, std::int64_t offset_, std::int32_t max_size_); + + static const std::int32_t ID = 540758376; + std::int32_t get_id() const final { + return ID; + } + + using ReturnType = object_ptr; + + static object_ptr fetch(td::TlParser &p); + + explicit tonNode_getArchiveSlice(td::TlParser &p); + + void store(td::TlStorerCalcLength &s) const final; + + void store(td::TlStorerUnsafe &s) const final; + + void store(td::TlStorerToString &s, const char *field_name) const final; + + static ReturnType fetch_result(td::TlParser &p); +}; + class tonNode_getCapabilities final : public Function { public: diff --git a/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api.hpp b/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api.hpp index 9216c063dc..e4df697cbd 100644 --- a/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api.hpp +++ b/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api.hpp @@ -296,9 +296,27 @@ bool downcast_call(Object &obj, const T &func) { case db_filedb_key_candidate::ID: func(static_cast(obj)); return true; + case db_filedb_key_blockInfo::ID: + func(static_cast(obj)); + return true; case db_filedb_value::ID: func(static_cast(obj)); return true; + case db_files_index_key::ID: + func(static_cast(obj)); + return true; + case db_files_package_key::ID: + func(static_cast(obj)); + return true; + case db_files_index_value::ID: + func(static_cast(obj)); + return true; + case db_files_package_firstBlock::ID: + func(static_cast(obj)); + return true; + case db_files_package_value::ID: + func(static_cast(obj)); + return true; case db_lt_el_key::ID: func(static_cast(obj)); return true; @@ -341,6 +359,9 @@ bool downcast_call(Object &obj, const T &func) { case db_state_asyncSerializer::ID: func(static_cast(obj)); return true; + case db_state_dbVersion::ID: + func(static_cast(obj)); + return true; case db_state_destroyedSessions::ID: func(static_cast(obj)); return true; @@ -371,6 +392,9 @@ bool downcast_call(Object &obj, const T &func) { case db_state_key_hardforks::ID: func(static_cast(obj)); return true; + case db_state_key_dbVersion::ID: + func(static_cast(obj)); + return true; case db_state_shardClient::ID: func(static_cast(obj)); return true; @@ -527,6 +551,24 @@ bool downcast_call(Object &obj, const T &func) { case fec_online::ID: func(static_cast(obj)); return true; + case http_header::ID: + func(static_cast(obj)); + return true; + case http_payloadPart::ID: + func(static_cast(obj)); + return true; + case http_response::ID: + func(static_cast(obj)); + return true; + case http_server_config::ID: + func(static_cast(obj)); + return true; + case http_server_dnsEntry::ID: + func(static_cast(obj)); + return true; + case http_server_host::ID: + func(static_cast(obj)); + return true; case id_config_local::ID: func(static_cast(obj)); return true; @@ -641,6 +683,12 @@ bool downcast_call(Object &obj, const T &func) { case ton_blockIdApprove::ID: func(static_cast(obj)); return true; + case tonNode_archiveNotFound::ID: + func(static_cast(obj)); + return true; + case tonNode_archiveInfo::ID: + func(static_cast(obj)); + return true; case tonNode_blockDescriptionEmpty::ID: func(static_cast(obj)); return true; @@ -937,6 +985,12 @@ bool downcast_call(Function &obj, const T &func) { case getTestObject::ID: func(static_cast(obj)); return true; + case http_getNextPayloadPart::ID: + func(static_cast(obj)); + return true; + case http_request::ID: + func(static_cast(obj)); + return true; case overlay_getBroadcast::ID: func(static_cast(obj)); return true; @@ -985,6 +1039,12 @@ bool downcast_call(Function &obj, const T &func) { case tonNode_downloadZeroState::ID: func(static_cast(obj)); return true; + case tonNode_getArchiveInfo::ID: + func(static_cast(obj)); + return true; + case tonNode_getArchiveSlice::ID: + func(static_cast(obj)); + return true; case tonNode_getCapabilities::ID: func(static_cast(obj)); return true; @@ -1407,6 +1467,29 @@ bool downcast_call(db_filedb_Key &obj, const T &func) { case db_filedb_key_candidate::ID: func(static_cast(obj)); return true; + case db_filedb_key_blockInfo::ID: + func(static_cast(obj)); + return true; + default: + return false; + } +} + +/** + * Calls specified function object with the specified object downcasted to the most-derived type. + * \param[in] obj Object to pass as an argument to the function object. + * \param[in] func Function object to which the object will be passed. + * \returns whether function object call has happened. Should always return true for correct parameters. + */ +template +bool downcast_call(db_files_Key &obj, const T &func) { + switch (obj.get_id()) { + case db_files_index_key::ID: + func(static_cast(obj)); + return true; + case db_files_package_key::ID: + func(static_cast(obj)); + return true; default: return false; } @@ -1488,6 +1571,9 @@ bool downcast_call(db_state_Key &obj, const T &func) { case db_state_key_hardforks::ID: func(static_cast(obj)); return true; + case db_state_key_dbVersion::ID: + func(static_cast(obj)); + return true; default: return false; } @@ -1763,6 +1849,26 @@ bool downcast_call(ton_BlockId &obj, const T &func) { } } +/** + * Calls specified function object with the specified object downcasted to the most-derived type. + * \param[in] obj Object to pass as an argument to the function object. + * \param[in] func Function object to which the object will be passed. + * \returns whether function object call has happened. Should always return true for correct parameters. + */ +template +bool downcast_call(tonNode_ArchiveInfo &obj, const T &func) { + switch (obj.get_id()) { + case tonNode_archiveNotFound::ID: + func(static_cast(obj)); + return true; + case tonNode_archiveInfo::ID: + func(static_cast(obj)); + return true; + default: + return false; + } +} + /** * Calls specified function object with the specified object downcasted to the most-derived type. * \param[in] obj Object to pass as an argument to the function object. diff --git a/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api_json.cpp b/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api_json.cpp index dde2c4fd45..9cf8386668 100644 --- a/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api_json.cpp +++ b/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api_json.cpp @@ -188,7 +188,19 @@ Result tl_constructor_from_string(ton_api::db_filedb_Key *object, const s {"db.filedb.key.proof", -627749396}, {"db.filedb.key.proofLink", -1728330290}, {"db.filedb.key.signatures", -685175541}, - {"db.filedb.key.candidate", -494269767} + {"db.filedb.key.candidate", -494269767}, + {"db.filedb.key.blockInfo", -996551428} + }; + auto it = m.find(str); + if (it == m.end()) { + return Status::Error(str + "Unknown class"); + } + return it->second; +} +Result tl_constructor_from_string(ton_api::db_files_Key *object, const std::string &str) { + static const std::unordered_map m = { + {"db.files.index.key", 2109998338}, + {"db.files.package.key", -1526463682} }; auto it = m.find(str); if (it == m.end()) { @@ -228,7 +240,8 @@ Result tl_constructor_from_string(ton_api::db_state_Key *object, const st {"db.state.key.gcBlockId", -1015417890}, {"db.state.key.shardClient", -912576121}, {"db.state.key.asyncSerializer", 699304479}, - {"db.state.key.hardforks", -420206662} + {"db.state.key.hardforks", -420206662}, + {"db.state.key.dbVersion", 1917788500} }; auto it = m.find(str); if (it == m.end()) { @@ -378,6 +391,17 @@ Result tl_constructor_from_string(ton_api::ton_BlockId *object, const std } return it->second; } +Result tl_constructor_from_string(ton_api::tonNode_ArchiveInfo *object, const std::string &str) { + static const std::unordered_map m = { + {"tonNode.archiveNotFound", -1725360509}, + {"tonNode.archiveInfo", 435158924} + }; + auto it = m.find(str); + if (it == m.end()) { + return Status::Error(str + "Unknown class"); + } + return it->second; +} Result tl_constructor_from_string(ton_api::tonNode_BlockDescription *object, const std::string &str) { static const std::unordered_map m = { {"tonNode.blockDescriptionEmpty", -2088456555}, @@ -593,7 +617,13 @@ Result tl_constructor_from_string(ton_api::Object *object, const std::str {"db.filedb.key.proofLink", -1728330290}, {"db.filedb.key.signatures", -685175541}, {"db.filedb.key.candidate", -494269767}, + {"db.filedb.key.blockInfo", -996551428}, {"db.filedb.value", -220390867}, + {"db.files.index.key", 2109998338}, + {"db.files.package.key", -1526463682}, + {"db.files.index.value", -1565402372}, + {"db.files.package.firstBlock", 1880254951}, + {"db.files.package.value", -464726741}, {"db.lt.el.key", -1523442974}, {"db.lt.desc.key", -236722287}, {"db.lt.shard.key", 1353120015}, @@ -608,6 +638,7 @@ Result tl_constructor_from_string(ton_api::Object *object, const std::str {"db.root.key.blockDb", 806534976}, {"db.root.key.config", 331559556}, {"db.state.asyncSerializer", -751883871}, + {"db.state.dbVersion", -650698505}, {"db.state.destroyedSessions", -1381443196}, {"db.state.gcBlockId", -550453937}, {"db.state.hardforks", -2047668988}, @@ -618,6 +649,7 @@ Result tl_constructor_from_string(ton_api::Object *object, const std::str {"db.state.key.shardClient", -912576121}, {"db.state.key.asyncSerializer", 699304479}, {"db.state.key.hardforks", -420206662}, + {"db.state.key.dbVersion", 1917788500}, {"db.state.shardClient", 186033821}, {"dht.key", -160964977}, {"dht.keyDescription", 673009157}, @@ -670,6 +702,12 @@ Result tl_constructor_from_string(ton_api::Object *object, const std::str {"fec.raptorQ", -1953257504}, {"fec.roundRobin", 854927588}, {"fec.online", 19359244}, + {"http.header", -1902385903}, + {"http.payloadPart", 693819236}, + {"http.response", -273307789}, + {"http.server.config", 974419964}, + {"http.server.dnsEntry", -663592810}, + {"http.server.host", -981605721}, {"id.config.local", -1834367090}, {"liteclient.config.global", 143507704}, {"liteserver.desc", -1001806732}, @@ -708,6 +746,8 @@ Result tl_constructor_from_string(ton_api::Object *object, const std::str {"tcp.pong", -597034237}, {"ton.blockId", -989106576}, {"ton.blockIdApprove", 768887369}, + {"tonNode.archiveNotFound", -1725360509}, + {"tonNode.archiveInfo", 435158924}, {"tonNode.blockDescriptionEmpty", -2088456555}, {"tonNode.blockDescription", 1185009800}, {"tonNode.blockId", -1211256473}, @@ -811,6 +851,8 @@ Result tl_constructor_from_string(ton_api::Function *object, const std::s {"engine.validator.setVerbosity", -1316856190}, {"engine.validator.sign", 451549736}, {"getTestObject", 197109379}, + {"http.getNextPayloadPart", -1871422196}, + {"http.request", 1639027169}, {"overlay.getBroadcast", 758510240}, {"overlay.getBroadcastList", 1109141562}, {"overlay.getRandomPeers", 1223582891}, @@ -827,6 +869,8 @@ Result tl_constructor_from_string(ton_api::Function *object, const std::s {"tonNode.downloadPersistentState", 2140791736}, {"tonNode.downloadPersistentStateSlice", -169220381}, {"tonNode.downloadZeroState", -1379131814}, + {"tonNode.getArchiveInfo", 2066602305}, + {"tonNode.getArchiveSlice", 540758376}, {"tonNode.getCapabilities", -555345672}, {"tonNode.getNextBlockDescription", 341160179}, {"tonNode.getNextBlocksDescription", 1059590852}, @@ -2116,6 +2160,12 @@ Status from_json(ton_api::db_block_info &to, JsonObject &from) { TRY_STATUS(from_json(to.state_, value)); } } + { + TRY_RESULT(value, get_json_object_field(from, "masterchain_ref_seqno", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.masterchain_ref_seqno_, value)); + } + } return Status::OK(); } Status from_json(ton_api::db_block_packedInfo &to, JsonObject &from) { @@ -2343,6 +2393,15 @@ Status from_json(ton_api::db_filedb_key_candidate &to, JsonObject &from) { } return Status::OK(); } +Status from_json(ton_api::db_filedb_key_blockInfo &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "block_id", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.block_id_, value)); + } + } + return Status::OK(); +} Status from_json(ton_api::db_filedb_value &to, JsonObject &from) { { TRY_RESULT(value, get_json_object_field(from, "key", JsonValue::Type::Null, true)); @@ -2370,6 +2429,117 @@ Status from_json(ton_api::db_filedb_value &to, JsonObject &from) { } return Status::OK(); } +Status from_json(ton_api::db_files_index_key &to, JsonObject &from) { + return Status::OK(); +} +Status from_json(ton_api::db_files_package_key &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "package_id", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.package_id_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "key", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.key_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "temp", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.temp_, value)); + } + } + return Status::OK(); +} +Status from_json(ton_api::db_files_index_value &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "packages", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.packages_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "key_packages", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.key_packages_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "temp_packages", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.temp_packages_, value)); + } + } + return Status::OK(); +} +Status from_json(ton_api::db_files_package_firstBlock &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "workchain", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.workchain_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "shard", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.shard_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "seqno", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.seqno_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "unixtime", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.unixtime_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "lt", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.lt_, value)); + } + } + return Status::OK(); +} +Status from_json(ton_api::db_files_package_value &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "package_id", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.package_id_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "key", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.key_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "temp", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.temp_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "firstblocks", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.firstblocks_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "deleted", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.deleted_, value)); + } + } + return Status::OK(); +} Status from_json(ton_api::db_lt_el_key &to, JsonObject &from) { { TRY_RESULT(value, get_json_object_field(from, "workchain", JsonValue::Type::Null, true)); @@ -2574,6 +2744,15 @@ Status from_json(ton_api::db_state_asyncSerializer &to, JsonObject &from) { } return Status::OK(); } +Status from_json(ton_api::db_state_dbVersion &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "version", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.version_, value)); + } + } + return Status::OK(); +} Status from_json(ton_api::db_state_destroyedSessions &to, JsonObject &from) { { TRY_RESULT(value, get_json_object_field(from, "sessions", JsonValue::Type::Null, true)); @@ -2628,6 +2807,9 @@ Status from_json(ton_api::db_state_key_asyncSerializer &to, JsonObject &from) { Status from_json(ton_api::db_state_key_hardforks &to, JsonObject &from) { return Status::OK(); } +Status from_json(ton_api::db_state_key_dbVersion &to, JsonObject &from) { + return Status::OK(); +} Status from_json(ton_api::db_state_shardClient &to, JsonObject &from) { { TRY_RESULT(value, get_json_object_field(from, "block", JsonValue::Type::Null, true)); @@ -3456,6 +3638,126 @@ Status from_json(ton_api::fec_online &to, JsonObject &from) { } return Status::OK(); } +Status from_json(ton_api::http_header &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "name", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.name_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "value", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.value_, value)); + } + } + return Status::OK(); +} +Status from_json(ton_api::http_payloadPart &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "data", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json_bytes(to.data_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "trailer", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.trailer_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "last", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.last_, value)); + } + } + return Status::OK(); +} +Status from_json(ton_api::http_response &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "http_version", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.http_version_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "status_code", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.status_code_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "reason", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.reason_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "headers", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.headers_, value)); + } + } + return Status::OK(); +} +Status from_json(ton_api::http_server_config &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "dhs", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.dhs_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "local_hosts", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.local_hosts_, value)); + } + } + return Status::OK(); +} +Status from_json(ton_api::http_server_dnsEntry &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "domain", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.domain_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "addr", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.addr_, value)); + } + } + return Status::OK(); +} +Status from_json(ton_api::http_server_host &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "domains", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.domains_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "ip", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.ip_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "port", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.port_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "adnl_id", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.adnl_id_, value)); + } + } + return Status::OK(); +} Status from_json(ton_api::id_config_local &to, JsonObject &from) { { TRY_RESULT(value, get_json_object_field(from, "id", JsonValue::Type::Null, true)); @@ -4146,6 +4448,18 @@ Status from_json(ton_api::ton_blockIdApprove &to, JsonObject &from) { } return Status::OK(); } +Status from_json(ton_api::tonNode_archiveNotFound &to, JsonObject &from) { + return Status::OK(); +} +Status from_json(ton_api::tonNode_archiveInfo &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "id", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.id_, value)); + } + } + return Status::OK(); +} Status from_json(ton_api::tonNode_blockDescriptionEmpty &to, JsonObject &from) { return Status::OK(); } @@ -5550,6 +5864,60 @@ Status from_json(ton_api::engine_validator_sign &to, JsonObject &from) { Status from_json(ton_api::getTestObject &to, JsonObject &from) { return Status::OK(); } +Status from_json(ton_api::http_getNextPayloadPart &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "id", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.id_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "seqno", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.seqno_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "max_chunk_size", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.max_chunk_size_, value)); + } + } + return Status::OK(); +} +Status from_json(ton_api::http_request &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "id", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.id_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "method", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.method_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "url", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.url_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "http_version", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.http_version_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "headers", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.headers_, value)); + } + } + return Status::OK(); +} Status from_json(ton_api::overlay_getBroadcast &to, JsonObject &from) { { TRY_RESULT(value, get_json_object_field(from, "hash", JsonValue::Type::Null, true)); @@ -5718,6 +6086,36 @@ Status from_json(ton_api::tonNode_downloadZeroState &to, JsonObject &from) { } return Status::OK(); } +Status from_json(ton_api::tonNode_getArchiveInfo &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "masterchain_seqno", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.masterchain_seqno_, value)); + } + } + return Status::OK(); +} +Status from_json(ton_api::tonNode_getArchiveSlice &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "archive_id", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.archive_id_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "offset", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.offset_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "max_size", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.max_size_, value)); + } + } + return Status::OK(); +} Status from_json(ton_api::tonNode_getCapabilities &to, JsonObject &from) { return Status::OK(); } @@ -6468,6 +6866,7 @@ void to_json(JsonValueScope &jv, const ton_api::db_block_info &object) { jo << ctie("lt", ToJson(JsonInt64{object.lt_})); jo << ctie("ts", ToJson(object.ts_)); jo << ctie("state", ToJson(object.state_)); + jo << ctie("masterchain_ref_seqno", ToJson(object.masterchain_ref_seqno_)); } void to_json(JsonValueScope &jv, const ton_api::db_block_packedInfo &object) { auto jo = jv.enter_object(); @@ -6610,6 +7009,13 @@ void to_json(JsonValueScope &jv, const ton_api::db_filedb_key_candidate &object) jo << ctie("id", ToJson(object.id_)); } } +void to_json(JsonValueScope &jv, const ton_api::db_filedb_key_blockInfo &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "db.filedb.key.blockInfo"); + if (object.block_id_) { + jo << ctie("block_id", ToJson(object.block_id_)); + } +} void to_json(JsonValueScope &jv, const ton_api::db_filedb_value &object) { auto jo = jv.enter_object(); jo << ctie("@type", "db.filedb.value"); @@ -6620,6 +7026,45 @@ void to_json(JsonValueScope &jv, const ton_api::db_filedb_value &object) { jo << ctie("next", ToJson(object.next_)); jo << ctie("file_hash", ToJson(object.file_hash_)); } +void to_json(JsonValueScope &jv, const ton_api::db_files_Key &object) { + ton_api::downcast_call(const_cast(object), [&jv](const auto &object) { to_json(jv, object); }); +} +void to_json(JsonValueScope &jv, const ton_api::db_files_index_key &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "db.files.index.key"); +} +void to_json(JsonValueScope &jv, const ton_api::db_files_package_key &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "db.files.package.key"); + jo << ctie("package_id", ToJson(object.package_id_)); + jo << ctie("key", ToJson(object.key_)); + jo << ctie("temp", ToJson(object.temp_)); +} +void to_json(JsonValueScope &jv, const ton_api::db_files_index_value &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "db.files.index.value"); + jo << ctie("packages", ToJson(object.packages_)); + jo << ctie("key_packages", ToJson(object.key_packages_)); + jo << ctie("temp_packages", ToJson(object.temp_packages_)); +} +void to_json(JsonValueScope &jv, const ton_api::db_files_package_firstBlock &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "db.files.package.firstBlock"); + jo << ctie("workchain", ToJson(object.workchain_)); + jo << ctie("shard", ToJson(JsonInt64{object.shard_})); + jo << ctie("seqno", ToJson(object.seqno_)); + jo << ctie("unixtime", ToJson(object.unixtime_)); + jo << ctie("lt", ToJson(JsonInt64{object.lt_})); +} +void to_json(JsonValueScope &jv, const ton_api::db_files_package_value &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "db.files.package.value"); + jo << ctie("package_id", ToJson(object.package_id_)); + jo << ctie("key", ToJson(object.key_)); + jo << ctie("temp", ToJson(object.temp_)); + jo << ctie("firstblocks", ToJson(object.firstblocks_)); + jo << ctie("deleted", ToJson(object.deleted_)); +} void to_json(JsonValueScope &jv, const ton_api::db_lt_Key &object) { ton_api::downcast_call(const_cast(object), [&jv](const auto &object) { to_json(jv, object); }); } @@ -6717,6 +7162,11 @@ void to_json(JsonValueScope &jv, const ton_api::db_state_asyncSerializer &object } jo << ctie("last_ts", ToJson(object.last_ts_)); } +void to_json(JsonValueScope &jv, const ton_api::db_state_dbVersion &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "db.state.dbVersion"); + jo << ctie("version", ToJson(object.version_)); +} void to_json(JsonValueScope &jv, const ton_api::db_state_destroyedSessions &object) { auto jo = jv.enter_object(); jo << ctie("@type", "db.state.destroyedSessions"); @@ -6768,6 +7218,10 @@ void to_json(JsonValueScope &jv, const ton_api::db_state_key_hardforks &object) auto jo = jv.enter_object(); jo << ctie("@type", "db.state.key.hardforks"); } +void to_json(JsonValueScope &jv, const ton_api::db_state_key_dbVersion &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "db.state.key.dbVersion"); +} void to_json(JsonValueScope &jv, const ton_api::db_state_shardClient &object) { auto jo = jv.enter_object(); jo << ctie("@type", "db.state.shardClient"); @@ -7139,6 +7593,51 @@ void to_json(JsonValueScope &jv, const ton_api::fec_online &object) { jo << ctie("symbol_size", ToJson(object.symbol_size_)); jo << ctie("symbols_count", ToJson(object.symbols_count_)); } +void to_json(JsonValueScope &jv, const ton_api::http_header &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "http.header"); + jo << ctie("name", ToJson(object.name_)); + jo << ctie("value", ToJson(object.value_)); +} +void to_json(JsonValueScope &jv, const ton_api::http_payloadPart &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "http.payloadPart"); + jo << ctie("data", ToJson(JsonBytes{object.data_})); + jo << ctie("trailer", ToJson(object.trailer_)); + jo << ctie("last", ToJson(object.last_)); +} +void to_json(JsonValueScope &jv, const ton_api::http_response &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "http.response"); + jo << ctie("http_version", ToJson(object.http_version_)); + jo << ctie("status_code", ToJson(object.status_code_)); + jo << ctie("reason", ToJson(object.reason_)); + jo << ctie("headers", ToJson(object.headers_)); +} +void to_json(JsonValueScope &jv, const ton_api::http_server_config &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "http.server.config"); + jo << ctie("dhs", ToJson(object.dhs_)); + jo << ctie("local_hosts", ToJson(object.local_hosts_)); +} +void to_json(JsonValueScope &jv, const ton_api::http_server_dnsEntry &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "http.server.dnsEntry"); + jo << ctie("domain", ToJson(object.domain_)); + if (object.addr_) { + jo << ctie("addr", ToJson(object.addr_)); + } +} +void to_json(JsonValueScope &jv, const ton_api::http_server_host &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "http.server.host"); + jo << ctie("domains", ToJson(object.domains_)); + jo << ctie("ip", ToJson(object.ip_)); + jo << ctie("port", ToJson(object.port_)); + if (object.adnl_id_) { + jo << ctie("adnl_id", ToJson(object.adnl_id_)); + } +} void to_json(JsonValueScope &jv, const ton_api::id_config_local &object) { auto jo = jv.enter_object(); jo << ctie("@type", "id.config.local"); @@ -7442,6 +7941,18 @@ void to_json(JsonValueScope &jv, const ton_api::ton_blockIdApprove &object) { jo << ctie("root_cell_hash", ToJson(object.root_cell_hash_)); jo << ctie("file_hash", ToJson(object.file_hash_)); } +void to_json(JsonValueScope &jv, const ton_api::tonNode_ArchiveInfo &object) { + ton_api::downcast_call(const_cast(object), [&jv](const auto &object) { to_json(jv, object); }); +} +void to_json(JsonValueScope &jv, const ton_api::tonNode_archiveNotFound &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "tonNode.archiveNotFound"); +} +void to_json(JsonValueScope &jv, const ton_api::tonNode_archiveInfo &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "tonNode.archiveInfo"); + jo << ctie("id", ToJson(JsonInt64{object.id_})); +} void to_json(JsonValueScope &jv, const ton_api::tonNode_BlockDescription &object) { ton_api::downcast_call(const_cast(object), [&jv](const auto &object) { to_json(jv, object); }); } @@ -8065,6 +8576,22 @@ void to_json(JsonValueScope &jv, const ton_api::getTestObject &object) { auto jo = jv.enter_object(); jo << ctie("@type", "getTestObject"); } +void to_json(JsonValueScope &jv, const ton_api::http_getNextPayloadPart &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "http.getNextPayloadPart"); + jo << ctie("id", ToJson(object.id_)); + jo << ctie("seqno", ToJson(object.seqno_)); + jo << ctie("max_chunk_size", ToJson(object.max_chunk_size_)); +} +void to_json(JsonValueScope &jv, const ton_api::http_request &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "http.request"); + jo << ctie("id", ToJson(object.id_)); + jo << ctie("method", ToJson(object.method_)); + jo << ctie("url", ToJson(object.url_)); + jo << ctie("http_version", ToJson(object.http_version_)); + jo << ctie("headers", ToJson(object.headers_)); +} void to_json(JsonValueScope &jv, const ton_api::overlay_getBroadcast &object) { auto jo = jv.enter_object(); jo << ctie("@type", "overlay.getBroadcast"); @@ -8173,6 +8700,18 @@ void to_json(JsonValueScope &jv, const ton_api::tonNode_downloadZeroState &objec jo << ctie("block", ToJson(object.block_)); } } +void to_json(JsonValueScope &jv, const ton_api::tonNode_getArchiveInfo &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "tonNode.getArchiveInfo"); + jo << ctie("masterchain_seqno", ToJson(object.masterchain_seqno_)); +} +void to_json(JsonValueScope &jv, const ton_api::tonNode_getArchiveSlice &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "tonNode.getArchiveSlice"); + jo << ctie("archive_id", ToJson(JsonInt64{object.archive_id_})); + jo << ctie("offset", ToJson(JsonInt64{object.offset_})); + jo << ctie("max_size", ToJson(object.max_size_)); +} void to_json(JsonValueScope &jv, const ton_api::tonNode_getCapabilities &object) { auto jo = jv.enter_object(); jo << ctie("@type", "tonNode.getCapabilities"); diff --git a/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api_json.h b/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api_json.h index b7fbcebbc5..d7cc42728f 100644 --- a/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api_json.h +++ b/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api_json.h @@ -24,6 +24,7 @@ Result tl_constructor_from_string(ton_api::catchain_block_inner_Data *obj Result tl_constructor_from_string(ton_api::db_block_Info *object, const std::string &str); Result tl_constructor_from_string(ton_api::db_blockdb_Key *object, const std::string &str); Result tl_constructor_from_string(ton_api::db_filedb_Key *object, const std::string &str); +Result tl_constructor_from_string(ton_api::db_files_Key *object, const std::string &str); Result tl_constructor_from_string(ton_api::db_lt_Key *object, const std::string &str); Result tl_constructor_from_string(ton_api::db_root_Key *object, const std::string &str); Result tl_constructor_from_string(ton_api::db_state_Key *object, const std::string &str); @@ -39,6 +40,7 @@ Result tl_constructor_from_string(ton_api::rldp_Message *object, const st Result tl_constructor_from_string(ton_api::rldp_MessagePart *object, const std::string &str); Result tl_constructor_from_string(ton_api::tcp_Message *object, const std::string &str); Result tl_constructor_from_string(ton_api::ton_BlockId *object, const std::string &str); +Result tl_constructor_from_string(ton_api::tonNode_ArchiveInfo *object, const std::string &str); Result tl_constructor_from_string(ton_api::tonNode_BlockDescription *object, const std::string &str); Result tl_constructor_from_string(ton_api::tonNode_Broadcast *object, const std::string &str); Result tl_constructor_from_string(ton_api::tonNode_DataFull *object, const std::string &str); @@ -145,7 +147,13 @@ Status from_json(ton_api::db_filedb_key_proof &to, JsonObject &from); Status from_json(ton_api::db_filedb_key_proofLink &to, JsonObject &from); Status from_json(ton_api::db_filedb_key_signatures &to, JsonObject &from); Status from_json(ton_api::db_filedb_key_candidate &to, JsonObject &from); +Status from_json(ton_api::db_filedb_key_blockInfo &to, JsonObject &from); Status from_json(ton_api::db_filedb_value &to, JsonObject &from); +Status from_json(ton_api::db_files_index_key &to, JsonObject &from); +Status from_json(ton_api::db_files_package_key &to, JsonObject &from); +Status from_json(ton_api::db_files_index_value &to, JsonObject &from); +Status from_json(ton_api::db_files_package_firstBlock &to, JsonObject &from); +Status from_json(ton_api::db_files_package_value &to, JsonObject &from); Status from_json(ton_api::db_lt_el_key &to, JsonObject &from); Status from_json(ton_api::db_lt_desc_key &to, JsonObject &from); Status from_json(ton_api::db_lt_shard_key &to, JsonObject &from); @@ -160,6 +168,7 @@ Status from_json(ton_api::db_root_key_cellDb &to, JsonObject &from); Status from_json(ton_api::db_root_key_blockDb &to, JsonObject &from); Status from_json(ton_api::db_root_key_config &to, JsonObject &from); Status from_json(ton_api::db_state_asyncSerializer &to, JsonObject &from); +Status from_json(ton_api::db_state_dbVersion &to, JsonObject &from); Status from_json(ton_api::db_state_destroyedSessions &to, JsonObject &from); Status from_json(ton_api::db_state_gcBlockId &to, JsonObject &from); Status from_json(ton_api::db_state_hardforks &to, JsonObject &from); @@ -170,6 +179,7 @@ Status from_json(ton_api::db_state_key_gcBlockId &to, JsonObject &from); Status from_json(ton_api::db_state_key_shardClient &to, JsonObject &from); Status from_json(ton_api::db_state_key_asyncSerializer &to, JsonObject &from); Status from_json(ton_api::db_state_key_hardforks &to, JsonObject &from); +Status from_json(ton_api::db_state_key_dbVersion &to, JsonObject &from); Status from_json(ton_api::db_state_shardClient &to, JsonObject &from); Status from_json(ton_api::dht_key &to, JsonObject &from); Status from_json(ton_api::dht_keyDescription &to, JsonObject &from); @@ -222,6 +232,12 @@ Status from_json(ton_api::engine_validator_time &to, JsonObject &from); Status from_json(ton_api::fec_raptorQ &to, JsonObject &from); Status from_json(ton_api::fec_roundRobin &to, JsonObject &from); Status from_json(ton_api::fec_online &to, JsonObject &from); +Status from_json(ton_api::http_header &to, JsonObject &from); +Status from_json(ton_api::http_payloadPart &to, JsonObject &from); +Status from_json(ton_api::http_response &to, JsonObject &from); +Status from_json(ton_api::http_server_config &to, JsonObject &from); +Status from_json(ton_api::http_server_dnsEntry &to, JsonObject &from); +Status from_json(ton_api::http_server_host &to, JsonObject &from); Status from_json(ton_api::id_config_local &to, JsonObject &from); Status from_json(ton_api::liteclient_config_global &to, JsonObject &from); Status from_json(ton_api::liteserver_desc &to, JsonObject &from); @@ -260,6 +276,8 @@ Status from_json(ton_api::tcp_authentificationComplete &to, JsonObject &from); Status from_json(ton_api::tcp_pong &to, JsonObject &from); Status from_json(ton_api::ton_blockId &to, JsonObject &from); Status from_json(ton_api::ton_blockIdApprove &to, JsonObject &from); +Status from_json(ton_api::tonNode_archiveNotFound &to, JsonObject &from); +Status from_json(ton_api::tonNode_archiveInfo &to, JsonObject &from); Status from_json(ton_api::tonNode_blockDescriptionEmpty &to, JsonObject &from); Status from_json(ton_api::tonNode_blockDescription &to, JsonObject &from); Status from_json(ton_api::tonNode_blockId &to, JsonObject &from); @@ -354,6 +372,8 @@ Status from_json(ton_api::engine_validator_importPrivateKey &to, JsonObject &fro Status from_json(ton_api::engine_validator_setVerbosity &to, JsonObject &from); Status from_json(ton_api::engine_validator_sign &to, JsonObject &from); Status from_json(ton_api::getTestObject &to, JsonObject &from); +Status from_json(ton_api::http_getNextPayloadPart &to, JsonObject &from); +Status from_json(ton_api::http_request &to, JsonObject &from); Status from_json(ton_api::overlay_getBroadcast &to, JsonObject &from); Status from_json(ton_api::overlay_getBroadcastList &to, JsonObject &from); Status from_json(ton_api::overlay_getRandomPeers &to, JsonObject &from); @@ -370,6 +390,8 @@ Status from_json(ton_api::tonNode_downloadNextBlockFull &to, JsonObject &from); Status from_json(ton_api::tonNode_downloadPersistentState &to, JsonObject &from); Status from_json(ton_api::tonNode_downloadPersistentStateSlice &to, JsonObject &from); Status from_json(ton_api::tonNode_downloadZeroState &to, JsonObject &from); +Status from_json(ton_api::tonNode_getArchiveInfo &to, JsonObject &from); +Status from_json(ton_api::tonNode_getArchiveSlice &to, JsonObject &from); Status from_json(ton_api::tonNode_getCapabilities &to, JsonObject &from); Status from_json(ton_api::tonNode_getNextBlockDescription &to, JsonObject &from); Status from_json(ton_api::tonNode_getNextBlocksDescription &to, JsonObject &from); @@ -492,7 +514,14 @@ void to_json(JsonValueScope &jv, const ton_api::db_filedb_key_proof &object); void to_json(JsonValueScope &jv, const ton_api::db_filedb_key_proofLink &object); void to_json(JsonValueScope &jv, const ton_api::db_filedb_key_signatures &object); void to_json(JsonValueScope &jv, const ton_api::db_filedb_key_candidate &object); +void to_json(JsonValueScope &jv, const ton_api::db_filedb_key_blockInfo &object); void to_json(JsonValueScope &jv, const ton_api::db_filedb_value &object); +void to_json(JsonValueScope &jv, const ton_api::db_files_Key &object); +void to_json(JsonValueScope &jv, const ton_api::db_files_index_key &object); +void to_json(JsonValueScope &jv, const ton_api::db_files_package_key &object); +void to_json(JsonValueScope &jv, const ton_api::db_files_index_value &object); +void to_json(JsonValueScope &jv, const ton_api::db_files_package_firstBlock &object); +void to_json(JsonValueScope &jv, const ton_api::db_files_package_value &object); void to_json(JsonValueScope &jv, const ton_api::db_lt_Key &object); void to_json(JsonValueScope &jv, const ton_api::db_lt_el_key &object); void to_json(JsonValueScope &jv, const ton_api::db_lt_desc_key &object); @@ -509,6 +538,7 @@ void to_json(JsonValueScope &jv, const ton_api::db_root_key_cellDb &object); void to_json(JsonValueScope &jv, const ton_api::db_root_key_blockDb &object); void to_json(JsonValueScope &jv, const ton_api::db_root_key_config &object); void to_json(JsonValueScope &jv, const ton_api::db_state_asyncSerializer &object); +void to_json(JsonValueScope &jv, const ton_api::db_state_dbVersion &object); void to_json(JsonValueScope &jv, const ton_api::db_state_destroyedSessions &object); void to_json(JsonValueScope &jv, const ton_api::db_state_gcBlockId &object); void to_json(JsonValueScope &jv, const ton_api::db_state_hardforks &object); @@ -520,6 +550,7 @@ void to_json(JsonValueScope &jv, const ton_api::db_state_key_gcBlockId &object); void to_json(JsonValueScope &jv, const ton_api::db_state_key_shardClient &object); void to_json(JsonValueScope &jv, const ton_api::db_state_key_asyncSerializer &object); void to_json(JsonValueScope &jv, const ton_api::db_state_key_hardforks &object); +void to_json(JsonValueScope &jv, const ton_api::db_state_key_dbVersion &object); void to_json(JsonValueScope &jv, const ton_api::db_state_shardClient &object); void to_json(JsonValueScope &jv, const ton_api::dht_key &object); void to_json(JsonValueScope &jv, const ton_api::dht_keyDescription &object); @@ -577,6 +608,12 @@ void to_json(JsonValueScope &jv, const ton_api::fec_Type &object); void to_json(JsonValueScope &jv, const ton_api::fec_raptorQ &object); void to_json(JsonValueScope &jv, const ton_api::fec_roundRobin &object); void to_json(JsonValueScope &jv, const ton_api::fec_online &object); +void to_json(JsonValueScope &jv, const ton_api::http_header &object); +void to_json(JsonValueScope &jv, const ton_api::http_payloadPart &object); +void to_json(JsonValueScope &jv, const ton_api::http_response &object); +void to_json(JsonValueScope &jv, const ton_api::http_server_config &object); +void to_json(JsonValueScope &jv, const ton_api::http_server_dnsEntry &object); +void to_json(JsonValueScope &jv, const ton_api::http_server_host &object); void to_json(JsonValueScope &jv, const ton_api::id_config_local &object); void to_json(JsonValueScope &jv, const ton_api::liteclient_config_global &object); void to_json(JsonValueScope &jv, const ton_api::liteserver_desc &object); @@ -622,6 +659,9 @@ void to_json(JsonValueScope &jv, const ton_api::tcp_pong &object); void to_json(JsonValueScope &jv, const ton_api::ton_BlockId &object); void to_json(JsonValueScope &jv, const ton_api::ton_blockId &object); void to_json(JsonValueScope &jv, const ton_api::ton_blockIdApprove &object); +void to_json(JsonValueScope &jv, const ton_api::tonNode_ArchiveInfo &object); +void to_json(JsonValueScope &jv, const ton_api::tonNode_archiveNotFound &object); +void to_json(JsonValueScope &jv, const ton_api::tonNode_archiveInfo &object); void to_json(JsonValueScope &jv, const ton_api::tonNode_BlockDescription &object); void to_json(JsonValueScope &jv, const ton_api::tonNode_blockDescriptionEmpty &object); void to_json(JsonValueScope &jv, const ton_api::tonNode_blockDescription &object); @@ -726,6 +766,8 @@ void to_json(JsonValueScope &jv, const ton_api::engine_validator_importPrivateKe void to_json(JsonValueScope &jv, const ton_api::engine_validator_setVerbosity &object); void to_json(JsonValueScope &jv, const ton_api::engine_validator_sign &object); void to_json(JsonValueScope &jv, const ton_api::getTestObject &object); +void to_json(JsonValueScope &jv, const ton_api::http_getNextPayloadPart &object); +void to_json(JsonValueScope &jv, const ton_api::http_request &object); void to_json(JsonValueScope &jv, const ton_api::overlay_getBroadcast &object); void to_json(JsonValueScope &jv, const ton_api::overlay_getBroadcastList &object); void to_json(JsonValueScope &jv, const ton_api::overlay_getRandomPeers &object); @@ -742,6 +784,8 @@ void to_json(JsonValueScope &jv, const ton_api::tonNode_downloadNextBlockFull &o void to_json(JsonValueScope &jv, const ton_api::tonNode_downloadPersistentState &object); void to_json(JsonValueScope &jv, const ton_api::tonNode_downloadPersistentStateSlice &object); void to_json(JsonValueScope &jv, const ton_api::tonNode_downloadZeroState &object); +void to_json(JsonValueScope &jv, const ton_api::tonNode_getArchiveInfo &object); +void to_json(JsonValueScope &jv, const ton_api::tonNode_getArchiveSlice &object); void to_json(JsonValueScope &jv, const ton_api::tonNode_getCapabilities &object); void to_json(JsonValueScope &jv, const ton_api::tonNode_getNextBlockDescription &object); void to_json(JsonValueScope &jv, const ton_api::tonNode_getNextBlocksDescription &object); diff --git a/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api.cpp b/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api.cpp index 1facb43fa7..1b6fb98d11 100644 --- a/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api.cpp +++ b/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api.cpp @@ -37,6 +37,267 @@ void accountAddress::store(td::TlStorerToString &s, const char *field_name) cons } } +accountRevisionList::accountRevisionList() + : revisions_() +{} + +accountRevisionList::accountRevisionList(std::vector &&revisions_) + : revisions_(std::move(revisions_)) +{} + +const std::int32_t accountRevisionList::ID; + +void accountRevisionList::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "accountRevisionList"); + { const std::vector &v = revisions_; const std::uint32_t multiplicity = static_cast(v.size()); const auto vector_name = "vector[" + td::to_string(multiplicity)+ "]"; s.store_class_begin("revisions", vector_name.c_str()); for (std::uint32_t i = 0; i < multiplicity; i++) { s.store_field("", v[i]); } s.store_class_end(); } + s.store_class_end(); + } +} + +raw_accountState::raw_accountState() + : code_() + , data_() + , frozen_hash_() +{} + +raw_accountState::raw_accountState(std::string const &code_, std::string const &data_, std::string const &frozen_hash_) + : code_(std::move(code_)) + , data_(std::move(data_)) + , frozen_hash_(std::move(frozen_hash_)) +{} + +const std::int32_t raw_accountState::ID; + +void raw_accountState::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "raw_accountState"); + s.store_bytes_field("code", code_); + s.store_bytes_field("data", data_); + s.store_bytes_field("frozen_hash", frozen_hash_); + s.store_class_end(); + } +} + +testWallet_accountState::testWallet_accountState() + : seqno_() +{} + +testWallet_accountState::testWallet_accountState(std::int32_t seqno_) + : seqno_(seqno_) +{} + +const std::int32_t testWallet_accountState::ID; + +void testWallet_accountState::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "testWallet_accountState"); + s.store_field("seqno", seqno_); + s.store_class_end(); + } +} + +wallet_accountState::wallet_accountState() + : seqno_() +{} + +wallet_accountState::wallet_accountState(std::int32_t seqno_) + : seqno_(seqno_) +{} + +const std::int32_t wallet_accountState::ID; + +void wallet_accountState::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "wallet_accountState"); + s.store_field("seqno", seqno_); + s.store_class_end(); + } +} + +wallet_v3_accountState::wallet_v3_accountState() + : wallet_id_() + , seqno_() +{} + +wallet_v3_accountState::wallet_v3_accountState(std::int64_t wallet_id_, std::int32_t seqno_) + : wallet_id_(wallet_id_) + , seqno_(seqno_) +{} + +const std::int32_t wallet_v3_accountState::ID; + +void wallet_v3_accountState::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "wallet_v3_accountState"); + s.store_field("wallet_id", wallet_id_); + s.store_field("seqno", seqno_); + s.store_class_end(); + } +} + +wallet_highload_v1_accountState::wallet_highload_v1_accountState() + : wallet_id_() + , seqno_() +{} + +wallet_highload_v1_accountState::wallet_highload_v1_accountState(std::int64_t wallet_id_, std::int32_t seqno_) + : wallet_id_(wallet_id_) + , seqno_(seqno_) +{} + +const std::int32_t wallet_highload_v1_accountState::ID; + +void wallet_highload_v1_accountState::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "wallet_highload_v1_accountState"); + s.store_field("wallet_id", wallet_id_); + s.store_field("seqno", seqno_); + s.store_class_end(); + } +} + +wallet_highload_v2_accountState::wallet_highload_v2_accountState() + : wallet_id_() +{} + +wallet_highload_v2_accountState::wallet_highload_v2_accountState(std::int64_t wallet_id_) + : wallet_id_(wallet_id_) +{} + +const std::int32_t wallet_highload_v2_accountState::ID; + +void wallet_highload_v2_accountState::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "wallet_highload_v2_accountState"); + s.store_field("wallet_id", wallet_id_); + s.store_class_end(); + } +} + +testGiver_accountState::testGiver_accountState() + : seqno_() +{} + +testGiver_accountState::testGiver_accountState(std::int32_t seqno_) + : seqno_(seqno_) +{} + +const std::int32_t testGiver_accountState::ID; + +void testGiver_accountState::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "testGiver_accountState"); + s.store_field("seqno", seqno_); + s.store_class_end(); + } +} + +dns_accountState::dns_accountState() + : wallet_id_() +{} + +dns_accountState::dns_accountState(std::int64_t wallet_id_) + : wallet_id_(wallet_id_) +{} + +const std::int32_t dns_accountState::ID; + +void dns_accountState::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "dns_accountState"); + s.store_field("wallet_id", wallet_id_); + s.store_class_end(); + } +} + +uninited_accountState::uninited_accountState() + : frozen_hash_() +{} + +uninited_accountState::uninited_accountState(std::string const &frozen_hash_) + : frozen_hash_(std::move(frozen_hash_)) +{} + +const std::int32_t uninited_accountState::ID; + +void uninited_accountState::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "uninited_accountState"); + s.store_bytes_field("frozen_hash", frozen_hash_); + s.store_class_end(); + } +} + +actionNoop::actionNoop() { +} + +const std::int32_t actionNoop::ID; + +void actionNoop::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "actionNoop"); + s.store_class_end(); + } +} + +actionMsg::actionMsg() + : messages_() + , allow_send_to_uninited_() +{} + +actionMsg::actionMsg(std::vector> &&messages_, bool allow_send_to_uninited_) + : messages_(std::move(messages_)) + , allow_send_to_uninited_(allow_send_to_uninited_) +{} + +const std::int32_t actionMsg::ID; + +void actionMsg::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "actionMsg"); + { const std::vector> &v = messages_; const std::uint32_t multiplicity = static_cast(v.size()); const auto vector_name = "vector[" + td::to_string(multiplicity)+ "]"; s.store_class_begin("messages", vector_name.c_str()); for (std::uint32_t i = 0; i < multiplicity; i++) { if (v[i] == nullptr) { s.store_field("", "null"); } else { v[i]->store(s, ""); } } s.store_class_end(); } + s.store_field("allow_send_to_uninited", allow_send_to_uninited_); + s.store_class_end(); + } +} + +actionDns::actionDns() + : actions_() +{} + +actionDns::actionDns(std::vector> &&actions_) + : actions_(std::move(actions_)) +{} + +const std::int32_t actionDns::ID; + +void actionDns::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "actionDns"); + { const std::vector> &v = actions_; const std::uint32_t multiplicity = static_cast(v.size()); const auto vector_name = "vector[" + td::to_string(multiplicity)+ "]"; s.store_class_begin("actions", vector_name.c_str()); for (std::uint32_t i = 0; i < multiplicity; i++) { if (v[i] == nullptr) { s.store_field("", "null"); } else { v[i]->store(s, ""); } } s.store_class_end(); } + s.store_class_end(); + } +} + +adnlAddress::adnlAddress() + : adnl_address_() +{} + +adnlAddress::adnlAddress(std::string const &adnl_address_) + : adnl_address_(std::move(adnl_address_)) +{} + +const std::int32_t adnlAddress::ID; + +void adnlAddress::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "adnlAddress"); + s.store_field("adnl_address", adnl_address_); + s.store_class_end(); + } +} + bip39Hints::bip39Hints() : words_() {} @@ -175,6 +436,24 @@ void exportedPemKey::store(td::TlStorerToString &s, const char *field_name) cons } } +exportedUnencryptedKey::exportedUnencryptedKey() + : data_() +{} + +exportedUnencryptedKey::exportedUnencryptedKey(td::SecureString &&data_) + : data_(std::move(data_)) +{} + +const std::int32_t exportedUnencryptedKey::ID; + +void exportedUnencryptedKey::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "exportedUnencryptedKey"); + s.store_bytes_field("data", data_); + s.store_class_end(); + } +} + fees::fees() : in_fwd_fee_() , storage_fee_() @@ -202,6 +481,189 @@ void fees::store(td::TlStorerToString &s, const char *field_name) const { } } +fullAccountState::fullAccountState() + : balance_() + , last_transaction_id_() + , block_id_() + , sync_utime_() + , account_state_() +{} + +fullAccountState::fullAccountState(std::int64_t balance_, object_ptr &&last_transaction_id_, object_ptr &&block_id_, std::int64_t sync_utime_, object_ptr &&account_state_) + : balance_(balance_) + , last_transaction_id_(std::move(last_transaction_id_)) + , block_id_(std::move(block_id_)) + , sync_utime_(sync_utime_) + , account_state_(std::move(account_state_)) +{} + +const std::int32_t fullAccountState::ID; + +void fullAccountState::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "fullAccountState"); + s.store_field("balance", balance_); + if (last_transaction_id_ == nullptr) { s.store_field("last_transaction_id", "null"); } else { last_transaction_id_->store(s, "last_transaction_id"); } + if (block_id_ == nullptr) { s.store_field("block_id", "null"); } else { block_id_->store(s, "block_id"); } + s.store_field("sync_utime", sync_utime_); + if (account_state_ == nullptr) { s.store_field("account_state", "null"); } else { account_state_->store(s, "account_state"); } + s.store_class_end(); + } +} + +raw_initialAccountState::raw_initialAccountState() + : code_() + , data_() +{} + +raw_initialAccountState::raw_initialAccountState(std::string const &code_, std::string const &data_) + : code_(std::move(code_)) + , data_(std::move(data_)) +{} + +const std::int32_t raw_initialAccountState::ID; + +void raw_initialAccountState::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "raw_initialAccountState"); + s.store_bytes_field("code", code_); + s.store_bytes_field("data", data_); + s.store_class_end(); + } +} + +testGiver_initialAccountState::testGiver_initialAccountState() { +} + +const std::int32_t testGiver_initialAccountState::ID; + +void testGiver_initialAccountState::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "testGiver_initialAccountState"); + s.store_class_end(); + } +} + +testWallet_initialAccountState::testWallet_initialAccountState() + : public_key_() +{} + +testWallet_initialAccountState::testWallet_initialAccountState(std::string const &public_key_) + : public_key_(std::move(public_key_)) +{} + +const std::int32_t testWallet_initialAccountState::ID; + +void testWallet_initialAccountState::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "testWallet_initialAccountState"); + s.store_field("public_key", public_key_); + s.store_class_end(); + } +} + +wallet_initialAccountState::wallet_initialAccountState() + : public_key_() +{} + +wallet_initialAccountState::wallet_initialAccountState(std::string const &public_key_) + : public_key_(std::move(public_key_)) +{} + +const std::int32_t wallet_initialAccountState::ID; + +void wallet_initialAccountState::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "wallet_initialAccountState"); + s.store_field("public_key", public_key_); + s.store_class_end(); + } +} + +wallet_v3_initialAccountState::wallet_v3_initialAccountState() + : public_key_() + , wallet_id_() +{} + +wallet_v3_initialAccountState::wallet_v3_initialAccountState(std::string const &public_key_, std::int64_t wallet_id_) + : public_key_(std::move(public_key_)) + , wallet_id_(wallet_id_) +{} + +const std::int32_t wallet_v3_initialAccountState::ID; + +void wallet_v3_initialAccountState::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "wallet_v3_initialAccountState"); + s.store_field("public_key", public_key_); + s.store_field("wallet_id", wallet_id_); + s.store_class_end(); + } +} + +wallet_highload_v1_initialAccountState::wallet_highload_v1_initialAccountState() + : public_key_() + , wallet_id_() +{} + +wallet_highload_v1_initialAccountState::wallet_highload_v1_initialAccountState(std::string const &public_key_, std::int64_t wallet_id_) + : public_key_(std::move(public_key_)) + , wallet_id_(wallet_id_) +{} + +const std::int32_t wallet_highload_v1_initialAccountState::ID; + +void wallet_highload_v1_initialAccountState::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "wallet_highload_v1_initialAccountState"); + s.store_field("public_key", public_key_); + s.store_field("wallet_id", wallet_id_); + s.store_class_end(); + } +} + +wallet_highload_v2_initialAccountState::wallet_highload_v2_initialAccountState() + : public_key_() + , wallet_id_() +{} + +wallet_highload_v2_initialAccountState::wallet_highload_v2_initialAccountState(std::string const &public_key_, std::int64_t wallet_id_) + : public_key_(std::move(public_key_)) + , wallet_id_(wallet_id_) +{} + +const std::int32_t wallet_highload_v2_initialAccountState::ID; + +void wallet_highload_v2_initialAccountState::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "wallet_highload_v2_initialAccountState"); + s.store_field("public_key", public_key_); + s.store_field("wallet_id", wallet_id_); + s.store_class_end(); + } +} + +dns_initialAccountState::dns_initialAccountState() + : public_key_() + , wallet_id_() +{} + +dns_initialAccountState::dns_initialAccountState(std::string const &public_key_, std::int64_t wallet_id_) + : public_key_(std::move(public_key_)) + , wallet_id_(wallet_id_) +{} + +const std::int32_t dns_initialAccountState::ID; + +void dns_initialAccountState::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "dns_initialAccountState"); + s.store_field("public_key", public_key_); + s.store_field("wallet_id", wallet_id_); + s.store_class_end(); + } +} + inputKeyRegular::inputKeyRegular() : key_() , local_password_() @@ -400,27 +862,6 @@ void options::store(td::TlStorerToString &s, const char *field_name) const { } } -sendGramsResult::sendGramsResult() - : sent_until_() - , body_hash_() -{} - -sendGramsResult::sendGramsResult(std::int64_t sent_until_, std::string const &body_hash_) - : sent_until_(sent_until_) - , body_hash_(std::move(body_hash_)) -{} - -const std::int32_t sendGramsResult::ID; - -void sendGramsResult::store(td::TlStorerToString &s, const char *field_name) const { - if (!LOG_IS_STRIPPED(ERROR)) { - s.store_class_begin(field_name, "sendGramsResult"); - s.store_field("sent_until", sent_until_); - s.store_bytes_field("body_hash", body_hash_); - s.store_class_end(); - } -} - syncStateDone::syncStateDone() { } @@ -523,110 +964,209 @@ void updateSyncState::store(td::TlStorerToString &s, const char *field_name) con } } -generic_accountStateRaw::generic_accountStateRaw() - : account_state_() -{} +dns_actionDeleteAll::dns_actionDeleteAll() { +} -generic_accountStateRaw::generic_accountStateRaw(object_ptr &&account_state_) - : account_state_(std::move(account_state_)) -{} +const std::int32_t dns_actionDeleteAll::ID; -const std::int32_t generic_accountStateRaw::ID; - -void generic_accountStateRaw::store(td::TlStorerToString &s, const char *field_name) const { +void dns_actionDeleteAll::store(td::TlStorerToString &s, const char *field_name) const { if (!LOG_IS_STRIPPED(ERROR)) { - s.store_class_begin(field_name, "generic_accountStateRaw"); - if (account_state_ == nullptr) { s.store_field("account_state", "null"); } else { account_state_->store(s, "account_state"); } + s.store_class_begin(field_name, "dns_actionDeleteAll"); s.store_class_end(); } } -generic_accountStateTestWallet::generic_accountStateTestWallet() - : account_state_() +dns_actionDelete::dns_actionDelete() + : name_() + , category_() {} -generic_accountStateTestWallet::generic_accountStateTestWallet(object_ptr &&account_state_) - : account_state_(std::move(account_state_)) +dns_actionDelete::dns_actionDelete(std::string const &name_, std::int32_t category_) + : name_(std::move(name_)) + , category_(category_) {} -const std::int32_t generic_accountStateTestWallet::ID; +const std::int32_t dns_actionDelete::ID; -void generic_accountStateTestWallet::store(td::TlStorerToString &s, const char *field_name) const { +void dns_actionDelete::store(td::TlStorerToString &s, const char *field_name) const { if (!LOG_IS_STRIPPED(ERROR)) { - s.store_class_begin(field_name, "generic_accountStateTestWallet"); - if (account_state_ == nullptr) { s.store_field("account_state", "null"); } else { account_state_->store(s, "account_state"); } + s.store_class_begin(field_name, "dns_actionDelete"); + s.store_field("name", name_); + s.store_field("category", category_); s.store_class_end(); } } -generic_accountStateWallet::generic_accountStateWallet() - : account_state_() +dns_actionSet::dns_actionSet() + : entry_() {} -generic_accountStateWallet::generic_accountStateWallet(object_ptr &&account_state_) - : account_state_(std::move(account_state_)) +dns_actionSet::dns_actionSet(object_ptr &&entry_) + : entry_(std::move(entry_)) {} -const std::int32_t generic_accountStateWallet::ID; +const std::int32_t dns_actionSet::ID; -void generic_accountStateWallet::store(td::TlStorerToString &s, const char *field_name) const { +void dns_actionSet::store(td::TlStorerToString &s, const char *field_name) const { if (!LOG_IS_STRIPPED(ERROR)) { - s.store_class_begin(field_name, "generic_accountStateWallet"); - if (account_state_ == nullptr) { s.store_field("account_state", "null"); } else { account_state_->store(s, "account_state"); } + s.store_class_begin(field_name, "dns_actionSet"); + if (entry_ == nullptr) { s.store_field("entry", "null"); } else { entry_->store(s, "entry"); } s.store_class_end(); } } -generic_accountStateWalletV3::generic_accountStateWalletV3() - : account_state_() +dns_entry::dns_entry() + : name_() + , category_() + , entry_() {} -generic_accountStateWalletV3::generic_accountStateWalletV3(object_ptr &&account_state_) - : account_state_(std::move(account_state_)) +dns_entry::dns_entry(std::string const &name_, std::int32_t category_, object_ptr &&entry_) + : name_(std::move(name_)) + , category_(category_) + , entry_(std::move(entry_)) {} -const std::int32_t generic_accountStateWalletV3::ID; +const std::int32_t dns_entry::ID; -void generic_accountStateWalletV3::store(td::TlStorerToString &s, const char *field_name) const { +void dns_entry::store(td::TlStorerToString &s, const char *field_name) const { if (!LOG_IS_STRIPPED(ERROR)) { - s.store_class_begin(field_name, "generic_accountStateWalletV3"); - if (account_state_ == nullptr) { s.store_field("account_state", "null"); } else { account_state_->store(s, "account_state"); } + s.store_class_begin(field_name, "dns_entry"); + s.store_field("name", name_); + s.store_field("category", category_); + if (entry_ == nullptr) { s.store_field("entry", "null"); } else { entry_->store(s, "entry"); } s.store_class_end(); } } -generic_accountStateTestGiver::generic_accountStateTestGiver() - : account_state_() +dns_entryDataUnknown::dns_entryDataUnknown() + : bytes_() {} -generic_accountStateTestGiver::generic_accountStateTestGiver(object_ptr &&account_state_) - : account_state_(std::move(account_state_)) +dns_entryDataUnknown::dns_entryDataUnknown(std::string const &bytes_) + : bytes_(std::move(bytes_)) {} -const std::int32_t generic_accountStateTestGiver::ID; +const std::int32_t dns_entryDataUnknown::ID; -void generic_accountStateTestGiver::store(td::TlStorerToString &s, const char *field_name) const { +void dns_entryDataUnknown::store(td::TlStorerToString &s, const char *field_name) const { if (!LOG_IS_STRIPPED(ERROR)) { - s.store_class_begin(field_name, "generic_accountStateTestGiver"); - if (account_state_ == nullptr) { s.store_field("account_state", "null"); } else { account_state_->store(s, "account_state"); } + s.store_class_begin(field_name, "dns_entryDataUnknown"); + s.store_bytes_field("bytes", bytes_); s.store_class_end(); } } -generic_accountStateUninited::generic_accountStateUninited() - : account_state_() +dns_entryDataText::dns_entryDataText() + : text_() {} -generic_accountStateUninited::generic_accountStateUninited(object_ptr &&account_state_) - : account_state_(std::move(account_state_)) +dns_entryDataText::dns_entryDataText(std::string const &text_) + : text_(std::move(text_)) {} -const std::int32_t generic_accountStateUninited::ID; +const std::int32_t dns_entryDataText::ID; -void generic_accountStateUninited::store(td::TlStorerToString &s, const char *field_name) const { +void dns_entryDataText::store(td::TlStorerToString &s, const char *field_name) const { if (!LOG_IS_STRIPPED(ERROR)) { - s.store_class_begin(field_name, "generic_accountStateUninited"); - if (account_state_ == nullptr) { s.store_field("account_state", "null"); } else { account_state_->store(s, "account_state"); } + s.store_class_begin(field_name, "dns_entryDataText"); + s.store_field("text", text_); + s.store_class_end(); + } +} + +dns_entryDataNextResolver::dns_entryDataNextResolver() + : resolver_() +{} + +dns_entryDataNextResolver::dns_entryDataNextResolver(object_ptr &&resolver_) + : resolver_(std::move(resolver_)) +{} + +const std::int32_t dns_entryDataNextResolver::ID; + +void dns_entryDataNextResolver::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "dns_entryDataNextResolver"); + if (resolver_ == nullptr) { s.store_field("resolver", "null"); } else { resolver_->store(s, "resolver"); } + s.store_class_end(); + } +} + +dns_entryDataSmcAddress::dns_entryDataSmcAddress() + : smc_address_() +{} + +dns_entryDataSmcAddress::dns_entryDataSmcAddress(object_ptr &&smc_address_) + : smc_address_(std::move(smc_address_)) +{} + +const std::int32_t dns_entryDataSmcAddress::ID; + +void dns_entryDataSmcAddress::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "dns_entryDataSmcAddress"); + if (smc_address_ == nullptr) { s.store_field("smc_address", "null"); } else { smc_address_->store(s, "smc_address"); } + s.store_class_end(); + } +} + +dns_entryDataAdnlAddress::dns_entryDataAdnlAddress() + : adnl_address_() +{} + +dns_entryDataAdnlAddress::dns_entryDataAdnlAddress(object_ptr &&adnl_address_) + : adnl_address_(std::move(adnl_address_)) +{} + +const std::int32_t dns_entryDataAdnlAddress::ID; + +void dns_entryDataAdnlAddress::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "dns_entryDataAdnlAddress"); + if (adnl_address_ == nullptr) { s.store_field("adnl_address", "null"); } else { adnl_address_->store(s, "adnl_address"); } + s.store_class_end(); + } +} + +dns_resolved::dns_resolved() + : entries_() +{} + +dns_resolved::dns_resolved(std::vector> &&entries_) + : entries_(std::move(entries_)) +{} + +const std::int32_t dns_resolved::ID; + +void dns_resolved::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "dns_resolved"); + { const std::vector> &v = entries_; const std::uint32_t multiplicity = static_cast(v.size()); const auto vector_name = "vector[" + td::to_string(multiplicity)+ "]"; s.store_class_begin("entries", vector_name.c_str()); for (std::uint32_t i = 0; i < multiplicity; i++) { if (v[i] == nullptr) { s.store_field("", "null"); } else { v[i]->store(s, ""); } } s.store_class_end(); } + s.store_class_end(); + } +} + +ton_blockId::ton_blockId() + : workchain_() + , shard_() + , seqno_() +{} + +ton_blockId::ton_blockId(std::int32_t workchain_, std::int64_t shard_, std::int32_t seqno_) + : workchain_(workchain_) + , shard_(shard_) + , seqno_(seqno_) +{} + +const std::int32_t ton_blockId::ID; + +void ton_blockId::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "ton_blockId"); + s.store_field("workchain", workchain_); + s.store_field("shard", shard_); + s.store_field("seqno", seqno_); s.store_class_end(); } } @@ -676,6 +1216,120 @@ void liteServer_info::store(td::TlStorerToString &s, const char *field_name) con } } +msg_dataRaw::msg_dataRaw() + : body_() +{} + +msg_dataRaw::msg_dataRaw(std::string const &body_) + : body_(std::move(body_)) +{} + +const std::int32_t msg_dataRaw::ID; + +void msg_dataRaw::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "msg_dataRaw"); + s.store_bytes_field("body", body_); + s.store_class_end(); + } +} + +msg_dataText::msg_dataText() + : text_() +{} + +msg_dataText::msg_dataText(std::string const &text_) + : text_(std::move(text_)) +{} + +const std::int32_t msg_dataText::ID; + +void msg_dataText::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "msg_dataText"); + s.store_bytes_field("text", text_); + s.store_class_end(); + } +} + +msg_dataDecryptedText::msg_dataDecryptedText() + : text_() +{} + +msg_dataDecryptedText::msg_dataDecryptedText(std::string const &text_) + : text_(std::move(text_)) +{} + +const std::int32_t msg_dataDecryptedText::ID; + +void msg_dataDecryptedText::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "msg_dataDecryptedText"); + s.store_bytes_field("text", text_); + s.store_class_end(); + } +} + +msg_dataEncryptedText::msg_dataEncryptedText() + : text_() +{} + +msg_dataEncryptedText::msg_dataEncryptedText(std::string const &text_) + : text_(std::move(text_)) +{} + +const std::int32_t msg_dataEncryptedText::ID; + +void msg_dataEncryptedText::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "msg_dataEncryptedText"); + s.store_bytes_field("text", text_); + s.store_class_end(); + } +} + +msg_dataArray::msg_dataArray() + : elements_() +{} + +msg_dataArray::msg_dataArray(std::vector> &&elements_) + : elements_(std::move(elements_)) +{} + +const std::int32_t msg_dataArray::ID; + +void msg_dataArray::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "msg_dataArray"); + { const std::vector> &v = elements_; const std::uint32_t multiplicity = static_cast(v.size()); const auto vector_name = "vector[" + td::to_string(multiplicity)+ "]"; s.store_class_begin("elements", vector_name.c_str()); for (std::uint32_t i = 0; i < multiplicity; i++) { if (v[i] == nullptr) { s.store_field("", "null"); } else { v[i]->store(s, ""); } } s.store_class_end(); } + s.store_class_end(); + } +} + +msg_message::msg_message() + : destination_() + , amount_() + , data_() +{} + +msg_message::msg_message(object_ptr &&destination_, std::int64_t amount_, object_ptr &&data_) + : destination_(std::move(destination_)) + , amount_(amount_) + , data_(std::move(data_)) +{} + +const std::int32_t msg_message::ID; + +void msg_message::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "msg_message"); + if (destination_ == nullptr) { s.store_field("destination", "null"); } else { destination_->store(s, "destination"); } + s.store_field("amount", amount_); + if (data_ == nullptr) { s.store_field("data", "null"); } else { data_->store(s, "data"); } + s.store_class_end(); + } +} + options_configInfo::options_configInfo() : default_wallet_id_() {} @@ -694,12 +1348,30 @@ void options_configInfo::store(td::TlStorerToString &s, const char *field_name) } } +options_info::options_info() + : config_info_() +{} + +options_info::options_info(object_ptr &&config_info_) + : config_info_(std::move(config_info_)) +{} + +const std::int32_t options_info::ID; + +void options_info::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "options_info"); + if (config_info_ == nullptr) { s.store_field("config_info", "null"); } else { config_info_->store(s, "config_info"); } + s.store_class_end(); + } +} + query_fees::query_fees() : source_fees_() , destination_fees_() {} -query_fees::query_fees(object_ptr &&source_fees_, object_ptr &&destination_fees_) +query_fees::query_fees(object_ptr &&source_fees_, std::vector> &&destination_fees_) : source_fees_(std::move(source_fees_)) , destination_fees_(std::move(destination_fees_)) {} @@ -710,7 +1382,7 @@ void query_fees::store(td::TlStorerToString &s, const char *field_name) const { if (!LOG_IS_STRIPPED(ERROR)) { s.store_class_begin(field_name, "query_fees"); if (source_fees_ == nullptr) { s.store_field("source_fees", "null"); } else { source_fees_->store(s, "source_fees"); } - if (destination_fees_ == nullptr) { s.store_field("destination_fees", "null"); } else { destination_fees_->store(s, "destination_fees"); } + { const std::vector> &v = destination_fees_; const std::uint32_t multiplicity = static_cast(v.size()); const auto vector_name = "vector[" + td::to_string(multiplicity)+ "]"; s.store_class_begin("destination_fees", vector_name.c_str()); for (std::uint32_t i = 0; i < multiplicity; i++) { if (v[i] == nullptr) { s.store_field("", "null"); } else { v[i]->store(s, ""); } } s.store_class_end(); } s.store_class_end(); } } @@ -739,60 +1411,42 @@ void query_info::store(td::TlStorerToString &s, const char *field_name) const { } } -raw_accountState::raw_accountState() +raw_fullAccountState::raw_fullAccountState() : balance_() , code_() , data_() , last_transaction_id_() + , block_id_() , frozen_hash_() , sync_utime_() {} -raw_accountState::raw_accountState(std::int64_t balance_, std::string const &code_, std::string const &data_, object_ptr &&last_transaction_id_, std::string const &frozen_hash_, std::int64_t sync_utime_) +raw_fullAccountState::raw_fullAccountState(std::int64_t balance_, std::string const &code_, std::string const &data_, object_ptr &&last_transaction_id_, object_ptr &&block_id_, std::string const &frozen_hash_, std::int64_t sync_utime_) : balance_(balance_) , code_(std::move(code_)) , data_(std::move(data_)) , last_transaction_id_(std::move(last_transaction_id_)) + , block_id_(std::move(block_id_)) , frozen_hash_(std::move(frozen_hash_)) , sync_utime_(sync_utime_) {} -const std::int32_t raw_accountState::ID; +const std::int32_t raw_fullAccountState::ID; -void raw_accountState::store(td::TlStorerToString &s, const char *field_name) const { +void raw_fullAccountState::store(td::TlStorerToString &s, const char *field_name) const { if (!LOG_IS_STRIPPED(ERROR)) { - s.store_class_begin(field_name, "raw_accountState"); + s.store_class_begin(field_name, "raw_fullAccountState"); s.store_field("balance", balance_); s.store_bytes_field("code", code_); s.store_bytes_field("data", data_); if (last_transaction_id_ == nullptr) { s.store_field("last_transaction_id", "null"); } else { last_transaction_id_->store(s, "last_transaction_id"); } + if (block_id_ == nullptr) { s.store_field("block_id", "null"); } else { block_id_->store(s, "block_id"); } s.store_bytes_field("frozen_hash", frozen_hash_); s.store_field("sync_utime", sync_utime_); s.store_class_end(); } } -raw_initialAccountState::raw_initialAccountState() - : code_() - , data_() -{} - -raw_initialAccountState::raw_initialAccountState(std::string const &code_, std::string const &data_) - : code_(std::move(code_)) - , data_(std::move(data_)) -{} - -const std::int32_t raw_initialAccountState::ID; - -void raw_initialAccountState::store(td::TlStorerToString &s, const char *field_name) const { - if (!LOG_IS_STRIPPED(ERROR)) { - s.store_class_begin(field_name, "raw_initialAccountState"); - s.store_bytes_field("code", code_); - s.store_bytes_field("data", data_); - s.store_class_end(); - } -} - raw_message::raw_message() : source_() , destination_() @@ -801,10 +1455,10 @@ raw_message::raw_message() , ihr_fee_() , created_lt_() , body_hash_() - , message_() + , msg_data_() {} -raw_message::raw_message(std::string const &source_, std::string const &destination_, std::int64_t value_, std::int64_t fwd_fee_, std::int64_t ihr_fee_, std::int64_t created_lt_, std::string const &body_hash_, std::string const &message_) +raw_message::raw_message(std::string const &source_, std::string const &destination_, std::int64_t value_, std::int64_t fwd_fee_, std::int64_t ihr_fee_, std::int64_t created_lt_, std::string const &body_hash_, object_ptr &&msg_data_) : source_(std::move(source_)) , destination_(std::move(destination_)) , value_(value_) @@ -812,7 +1466,7 @@ raw_message::raw_message(std::string const &source_, std::string const &destinat , ihr_fee_(ihr_fee_) , created_lt_(created_lt_) , body_hash_(std::move(body_hash_)) - , message_(std::move(message_)) + , msg_data_(std::move(msg_data_)) {} const std::int32_t raw_message::ID; @@ -827,7 +1481,7 @@ void raw_message::store(td::TlStorerToString &s, const char *field_name) const { s.store_field("ihr_fee", ihr_fee_); s.store_field("created_lt", created_lt_); s.store_bytes_field("body_hash", body_hash_); - s.store_bytes_field("message", message_); + if (msg_data_ == nullptr) { s.store_field("msg_data", "null"); } else { msg_data_->store(s, "msg_data"); } s.store_class_end(); } } @@ -970,74 +1624,32 @@ void smc_runResult::store(td::TlStorerToString &s, const char *field_name) const } } -testGiver_accountState::testGiver_accountState() - : balance_() +ton_blockIdExt::ton_blockIdExt() + : workchain_() + , shard_() , seqno_() - , last_transaction_id_() - , sync_utime_() + , root_hash_() + , file_hash_() {} -testGiver_accountState::testGiver_accountState(std::int64_t balance_, std::int32_t seqno_, object_ptr &&last_transaction_id_, std::int64_t sync_utime_) - : balance_(balance_) +ton_blockIdExt::ton_blockIdExt(std::int32_t workchain_, std::int64_t shard_, std::int32_t seqno_, std::string const &root_hash_, std::string const &file_hash_) + : workchain_(workchain_) + , shard_(shard_) , seqno_(seqno_) - , last_transaction_id_(std::move(last_transaction_id_)) - , sync_utime_(sync_utime_) + , root_hash_(std::move(root_hash_)) + , file_hash_(std::move(file_hash_)) {} -const std::int32_t testGiver_accountState::ID; +const std::int32_t ton_blockIdExt::ID; -void testGiver_accountState::store(td::TlStorerToString &s, const char *field_name) const { +void ton_blockIdExt::store(td::TlStorerToString &s, const char *field_name) const { if (!LOG_IS_STRIPPED(ERROR)) { - s.store_class_begin(field_name, "testGiver_accountState"); - s.store_field("balance", balance_); + s.store_class_begin(field_name, "ton_blockIdExt"); + s.store_field("workchain", workchain_); + s.store_field("shard", shard_); s.store_field("seqno", seqno_); - if (last_transaction_id_ == nullptr) { s.store_field("last_transaction_id", "null"); } else { last_transaction_id_->store(s, "last_transaction_id"); } - s.store_field("sync_utime", sync_utime_); - s.store_class_end(); - } -} - -testWallet_accountState::testWallet_accountState() - : balance_() - , seqno_() - , last_transaction_id_() - , sync_utime_() -{} - -testWallet_accountState::testWallet_accountState(std::int64_t balance_, std::int32_t seqno_, object_ptr &&last_transaction_id_, std::int64_t sync_utime_) - : balance_(balance_) - , seqno_(seqno_) - , last_transaction_id_(std::move(last_transaction_id_)) - , sync_utime_(sync_utime_) -{} - -const std::int32_t testWallet_accountState::ID; - -void testWallet_accountState::store(td::TlStorerToString &s, const char *field_name) const { - if (!LOG_IS_STRIPPED(ERROR)) { - s.store_class_begin(field_name, "testWallet_accountState"); - s.store_field("balance", balance_); - s.store_field("seqno", seqno_); - if (last_transaction_id_ == nullptr) { s.store_field("last_transaction_id", "null"); } else { last_transaction_id_->store(s, "last_transaction_id"); } - s.store_field("sync_utime", sync_utime_); - s.store_class_end(); - } -} - -testWallet_initialAccountState::testWallet_initialAccountState() - : public_key_() -{} - -testWallet_initialAccountState::testWallet_initialAccountState(std::string const &public_key_) - : public_key_(std::move(public_key_)) -{} - -const std::int32_t testWallet_initialAccountState::ID; - -void testWallet_initialAccountState::store(td::TlStorerToString &s, const char *field_name) const { - if (!LOG_IS_STRIPPED(ERROR)) { - s.store_class_begin(field_name, "testWallet_initialAccountState"); - s.store_field("public_key", public_key_); + s.store_bytes_field("root_hash", root_hash_); + s.store_bytes_field("file_hash", file_hash_); s.store_class_end(); } } @@ -1055,7 +1667,25 @@ const std::int32_t tvm_cell::ID; void tvm_cell::store(td::TlStorerToString &s, const char *field_name) const { if (!LOG_IS_STRIPPED(ERROR)) { s.store_class_begin(field_name, "tvm_cell"); - s.store_field("bytes", bytes_); + s.store_bytes_field("bytes", bytes_); + s.store_class_end(); + } +} + +tvm_list::tvm_list() + : elements_() +{} + +tvm_list::tvm_list(std::vector> &&elements_) + : elements_(std::move(elements_)) +{} + +const std::int32_t tvm_list::ID; + +void tvm_list::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "tvm_list"); + { const std::vector> &v = elements_; const std::uint32_t multiplicity = static_cast(v.size()); const auto vector_name = "vector[" + td::to_string(multiplicity)+ "]"; s.store_class_begin("elements", vector_name.c_str()); for (std::uint32_t i = 0; i < multiplicity; i++) { if (v[i] == nullptr) { s.store_field("", "null"); } else { v[i]->store(s, ""); } } s.store_class_end(); } s.store_class_end(); } } @@ -1091,7 +1721,7 @@ const std::int32_t tvm_slice::ID; void tvm_slice::store(td::TlStorerToString &s, const char *field_name) const { if (!LOG_IS_STRIPPED(ERROR)) { s.store_class_begin(field_name, "tvm_slice"); - s.store_field("bytes", bytes_); + s.store_bytes_field("bytes", bytes_); s.store_class_end(); } } @@ -1150,6 +1780,42 @@ void tvm_stackEntryNumber::store(td::TlStorerToString &s, const char *field_name } } +tvm_stackEntryTuple::tvm_stackEntryTuple() + : tuple_() +{} + +tvm_stackEntryTuple::tvm_stackEntryTuple(object_ptr &&tuple_) + : tuple_(std::move(tuple_)) +{} + +const std::int32_t tvm_stackEntryTuple::ID; + +void tvm_stackEntryTuple::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "tvm_stackEntryTuple"); + if (tuple_ == nullptr) { s.store_field("tuple", "null"); } else { tuple_->store(s, "tuple"); } + s.store_class_end(); + } +} + +tvm_stackEntryList::tvm_stackEntryList() + : list_() +{} + +tvm_stackEntryList::tvm_stackEntryList(object_ptr &&list_) + : list_(std::move(list_)) +{} + +const std::int32_t tvm_stackEntryList::ID; + +void tvm_stackEntryList::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "tvm_stackEntryList"); + if (list_ == nullptr) { s.store_field("list", "null"); } else { list_->store(s, "list"); } + s.store_class_end(); + } +} + tvm_stackEntryUnsupported::tvm_stackEntryUnsupported() { } @@ -1162,125 +1828,20 @@ void tvm_stackEntryUnsupported::store(td::TlStorerToString &s, const char *field } } -uninited_accountState::uninited_accountState() - : balance_() - , last_transaction_id_() - , frozen_hash_() - , sync_utime_() +tvm_tuple::tvm_tuple() + : elements_() {} -uninited_accountState::uninited_accountState(std::int64_t balance_, object_ptr &&last_transaction_id_, std::string const &frozen_hash_, std::int64_t sync_utime_) - : balance_(balance_) - , last_transaction_id_(std::move(last_transaction_id_)) - , frozen_hash_(std::move(frozen_hash_)) - , sync_utime_(sync_utime_) +tvm_tuple::tvm_tuple(std::vector> &&elements_) + : elements_(std::move(elements_)) {} -const std::int32_t uninited_accountState::ID; +const std::int32_t tvm_tuple::ID; -void uninited_accountState::store(td::TlStorerToString &s, const char *field_name) const { +void tvm_tuple::store(td::TlStorerToString &s, const char *field_name) const { if (!LOG_IS_STRIPPED(ERROR)) { - s.store_class_begin(field_name, "uninited_accountState"); - s.store_field("balance", balance_); - if (last_transaction_id_ == nullptr) { s.store_field("last_transaction_id", "null"); } else { last_transaction_id_->store(s, "last_transaction_id"); } - s.store_bytes_field("frozen_hash", frozen_hash_); - s.store_field("sync_utime", sync_utime_); - s.store_class_end(); - } -} - -wallet_accountState::wallet_accountState() - : balance_() - , seqno_() - , last_transaction_id_() - , sync_utime_() -{} - -wallet_accountState::wallet_accountState(std::int64_t balance_, std::int32_t seqno_, object_ptr &&last_transaction_id_, std::int64_t sync_utime_) - : balance_(balance_) - , seqno_(seqno_) - , last_transaction_id_(std::move(last_transaction_id_)) - , sync_utime_(sync_utime_) -{} - -const std::int32_t wallet_accountState::ID; - -void wallet_accountState::store(td::TlStorerToString &s, const char *field_name) const { - if (!LOG_IS_STRIPPED(ERROR)) { - s.store_class_begin(field_name, "wallet_accountState"); - s.store_field("balance", balance_); - s.store_field("seqno", seqno_); - if (last_transaction_id_ == nullptr) { s.store_field("last_transaction_id", "null"); } else { last_transaction_id_->store(s, "last_transaction_id"); } - s.store_field("sync_utime", sync_utime_); - s.store_class_end(); - } -} - -wallet_initialAccountState::wallet_initialAccountState() - : public_key_() -{} - -wallet_initialAccountState::wallet_initialAccountState(std::string const &public_key_) - : public_key_(std::move(public_key_)) -{} - -const std::int32_t wallet_initialAccountState::ID; - -void wallet_initialAccountState::store(td::TlStorerToString &s, const char *field_name) const { - if (!LOG_IS_STRIPPED(ERROR)) { - s.store_class_begin(field_name, "wallet_initialAccountState"); - s.store_field("public_key", public_key_); - s.store_class_end(); - } -} - -wallet_v3_accountState::wallet_v3_accountState() - : balance_() - , wallet_id_() - , seqno_() - , last_transaction_id_() - , sync_utime_() -{} - -wallet_v3_accountState::wallet_v3_accountState(std::int64_t balance_, std::int64_t wallet_id_, std::int32_t seqno_, object_ptr &&last_transaction_id_, std::int64_t sync_utime_) - : balance_(balance_) - , wallet_id_(wallet_id_) - , seqno_(seqno_) - , last_transaction_id_(std::move(last_transaction_id_)) - , sync_utime_(sync_utime_) -{} - -const std::int32_t wallet_v3_accountState::ID; - -void wallet_v3_accountState::store(td::TlStorerToString &s, const char *field_name) const { - if (!LOG_IS_STRIPPED(ERROR)) { - s.store_class_begin(field_name, "wallet_v3_accountState"); - s.store_field("balance", balance_); - s.store_field("wallet_id", wallet_id_); - s.store_field("seqno", seqno_); - if (last_transaction_id_ == nullptr) { s.store_field("last_transaction_id", "null"); } else { last_transaction_id_->store(s, "last_transaction_id"); } - s.store_field("sync_utime", sync_utime_); - s.store_class_end(); - } -} - -wallet_v3_initialAccountState::wallet_v3_initialAccountState() - : public_key_() - , wallet_id_() -{} - -wallet_v3_initialAccountState::wallet_v3_initialAccountState(std::string const &public_key_, std::int64_t wallet_id_) - : public_key_(std::move(public_key_)) - , wallet_id_(wallet_id_) -{} - -const std::int32_t wallet_v3_initialAccountState::ID; - -void wallet_v3_initialAccountState::store(td::TlStorerToString &s, const char *field_name) const { - if (!LOG_IS_STRIPPED(ERROR)) { - s.store_class_begin(field_name, "wallet_v3_initialAccountState"); - s.store_field("public_key", public_key_); - s.store_field("wallet_id", wallet_id_); + s.store_class_begin(field_name, "tvm_tuple"); + { const std::vector> &v = elements_; const std::uint32_t multiplicity = static_cast(v.size()); const auto vector_name = "vector[" + td::to_string(multiplicity)+ "]"; s.store_class_begin("elements", vector_name.c_str()); for (std::uint32_t i = 0; i < multiplicity; i++) { if (v[i] == nullptr) { s.store_field("", "null"); } else { v[i]->store(s, ""); } } s.store_class_end(); } s.store_class_end(); } } @@ -1363,6 +1924,33 @@ void createNewKey::store(td::TlStorerToString &s, const char *field_name) const } } +createQuery::createQuery() + : private_key_() + , address_() + , timeout_() + , action_() +{} + +createQuery::createQuery(object_ptr &&private_key_, object_ptr &&address_, std::int32_t timeout_, object_ptr &&action_) + : private_key_(std::move(private_key_)) + , address_(std::move(address_)) + , timeout_(timeout_) + , action_(std::move(action_)) +{} + +const std::int32_t createQuery::ID; + +void createQuery::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "createQuery"); + if (private_key_ == nullptr) { s.store_field("private_key", "null"); } else { private_key_->store(s, "private_key"); } + if (address_ == nullptr) { s.store_field("address", "null"); } else { address_->store(s, "address"); } + s.store_field("timeout", timeout_); + if (action_ == nullptr) { s.store_field("action", "null"); } else { action_->store(s, "action"); } + s.store_class_end(); + } +} + decrypt::decrypt() : encrypted_data_() , secret_() @@ -1414,6 +2002,33 @@ void deleteKey::store(td::TlStorerToString &s, const char *field_name) const { } } +dns_resolve::dns_resolve() + : account_address_() + , name_() + , category_() + , ttl_() +{} + +dns_resolve::dns_resolve(object_ptr &&account_address_, std::string const &name_, std::int32_t category_, std::int32_t ttl_) + : account_address_(std::move(account_address_)) + , name_(std::move(name_)) + , category_(category_) + , ttl_(ttl_) +{} + +const std::int32_t dns_resolve::ID; + +void dns_resolve::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "dns_resolve"); + if (account_address_ == nullptr) { s.store_field("account_address", "null"); } else { account_address_->store(s, "account_address"); } + s.store_field("name", name_); + s.store_field("category", category_); + s.store_field("ttl", ttl_); + s.store_class_end(); + } +} + encrypt::encrypt() : decrypted_data_() , secret_() @@ -1495,96 +2110,63 @@ void exportPemKey::store(td::TlStorerToString &s, const char *field_name) const } } -generic_createSendGramsQuery::generic_createSendGramsQuery() - : private_key_() - , source_() - , destination_() - , amount_() - , timeout_() - , allow_send_to_uninited_() - , message_() +exportUnencryptedKey::exportUnencryptedKey() + : input_key_() {} -generic_createSendGramsQuery::generic_createSendGramsQuery(object_ptr &&private_key_, object_ptr &&source_, object_ptr &&destination_, std::int64_t amount_, std::int32_t timeout_, bool allow_send_to_uninited_, std::string const &message_) - : private_key_(std::move(private_key_)) - , source_(std::move(source_)) - , destination_(std::move(destination_)) - , amount_(amount_) - , timeout_(timeout_) - , allow_send_to_uninited_(allow_send_to_uninited_) - , message_(std::move(message_)) +exportUnencryptedKey::exportUnencryptedKey(object_ptr &&input_key_) + : input_key_(std::move(input_key_)) {} -const std::int32_t generic_createSendGramsQuery::ID; +const std::int32_t exportUnencryptedKey::ID; -void generic_createSendGramsQuery::store(td::TlStorerToString &s, const char *field_name) const { +void exportUnencryptedKey::store(td::TlStorerToString &s, const char *field_name) const { if (!LOG_IS_STRIPPED(ERROR)) { - s.store_class_begin(field_name, "generic_createSendGramsQuery"); - if (private_key_ == nullptr) { s.store_field("private_key", "null"); } else { private_key_->store(s, "private_key"); } - if (source_ == nullptr) { s.store_field("source", "null"); } else { source_->store(s, "source"); } - if (destination_ == nullptr) { s.store_field("destination", "null"); } else { destination_->store(s, "destination"); } - s.store_field("amount", amount_); - s.store_field("timeout", timeout_); - s.store_field("allow_send_to_uninited", allow_send_to_uninited_); - s.store_bytes_field("message", message_); + s.store_class_begin(field_name, "exportUnencryptedKey"); + if (input_key_ == nullptr) { s.store_field("input_key", "null"); } else { input_key_->store(s, "input_key"); } s.store_class_end(); } } -generic_getAccountState::generic_getAccountState() +getAccountAddress::getAccountAddress() + : initial_account_state_() + , revision_() +{} + +getAccountAddress::getAccountAddress(object_ptr &&initial_account_state_, std::int32_t revision_) + : initial_account_state_(std::move(initial_account_state_)) + , revision_(revision_) +{} + +const std::int32_t getAccountAddress::ID; + +void getAccountAddress::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "getAccountAddress"); + if (initial_account_state_ == nullptr) { s.store_field("initial_account_state", "null"); } else { initial_account_state_->store(s, "initial_account_state"); } + s.store_field("revision", revision_); + s.store_class_end(); + } +} + +getAccountState::getAccountState() : account_address_() {} -generic_getAccountState::generic_getAccountState(object_ptr &&account_address_) +getAccountState::getAccountState(object_ptr &&account_address_) : account_address_(std::move(account_address_)) {} -const std::int32_t generic_getAccountState::ID; +const std::int32_t getAccountState::ID; -void generic_getAccountState::store(td::TlStorerToString &s, const char *field_name) const { +void getAccountState::store(td::TlStorerToString &s, const char *field_name) const { if (!LOG_IS_STRIPPED(ERROR)) { - s.store_class_begin(field_name, "generic_getAccountState"); + s.store_class_begin(field_name, "getAccountState"); if (account_address_ == nullptr) { s.store_field("account_address", "null"); } else { account_address_->store(s, "account_address"); } s.store_class_end(); } } -generic_sendGrams::generic_sendGrams() - : private_key_() - , source_() - , destination_() - , amount_() - , timeout_() - , allow_send_to_uninited_() - , message_() -{} - -generic_sendGrams::generic_sendGrams(object_ptr &&private_key_, object_ptr &&source_, object_ptr &&destination_, std::int64_t amount_, std::int32_t timeout_, bool allow_send_to_uninited_, std::string const &message_) - : private_key_(std::move(private_key_)) - , source_(std::move(source_)) - , destination_(std::move(destination_)) - , amount_(amount_) - , timeout_(timeout_) - , allow_send_to_uninited_(allow_send_to_uninited_) - , message_(std::move(message_)) -{} - -const std::int32_t generic_sendGrams::ID; - -void generic_sendGrams::store(td::TlStorerToString &s, const char *field_name) const { - if (!LOG_IS_STRIPPED(ERROR)) { - s.store_class_begin(field_name, "generic_sendGrams"); - if (private_key_ == nullptr) { s.store_field("private_key", "null"); } else { private_key_->store(s, "private_key"); } - if (source_ == nullptr) { s.store_field("source", "null"); } else { source_->store(s, "source"); } - if (destination_ == nullptr) { s.store_field("destination", "null"); } else { destination_->store(s, "destination"); } - s.store_field("amount", amount_); - s.store_field("timeout", timeout_); - s.store_field("allow_send_to_uninited", allow_send_to_uninited_); - s.store_bytes_field("message", message_); - s.store_class_end(); - } -} - getBip39Hints::getBip39Hints() : prefix_() {} @@ -1657,6 +2239,24 @@ void getLogVerbosityLevel::store(td::TlStorerToString &s, const char *field_name } } +guessAccountRevision::guessAccountRevision() + : initial_account_state_() +{} + +guessAccountRevision::guessAccountRevision(object_ptr &&initial_account_state_) + : initial_account_state_(std::move(initial_account_state_)) +{} + +const std::int32_t guessAccountRevision::ID; + +void guessAccountRevision::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "guessAccountRevision"); + if (initial_account_state_ == nullptr) { s.store_field("initial_account_state", "null"); } else { initial_account_state_->store(s, "initial_account_state"); } + s.store_class_end(); + } +} + importEncryptedKey::importEncryptedKey() : local_password_() , key_password_() @@ -1729,6 +2329,27 @@ void importPemKey::store(td::TlStorerToString &s, const char *field_name) const } } +importUnencryptedKey::importUnencryptedKey() + : local_password_() + , exported_unencrypted_key_() +{} + +importUnencryptedKey::importUnencryptedKey(td::SecureString &&local_password_, object_ptr &&exported_unencrypted_key_) + : local_password_(std::move(local_password_)) + , exported_unencrypted_key_(std::move(exported_unencrypted_key_)) +{} + +const std::int32_t importUnencryptedKey::ID; + +void importUnencryptedKey::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "importUnencryptedKey"); + s.store_bytes_field("local_password", local_password_); + if (exported_unencrypted_key_ == nullptr) { s.store_field("exported_unencrypted_key", "null"); } else { exported_unencrypted_key_->store(s, "exported_unencrypted_key"); } + s.store_class_end(); + } +} + init::init() : options_() {} @@ -1783,6 +2404,27 @@ void liteServer_getInfo::store(td::TlStorerToString &s, const char *field_name) } } +msg_decrypt::msg_decrypt() + : input_key_() + , data_() +{} + +msg_decrypt::msg_decrypt(object_ptr &&input_key_, object_ptr &&data_) + : input_key_(std::move(input_key_)) + , data_(std::move(data_)) +{} + +const std::int32_t msg_decrypt::ID; + +void msg_decrypt::store(td::TlStorerToString &s, const char *field_name) const { + if (!LOG_IS_STRIPPED(ERROR)) { + s.store_class_begin(field_name, "msg_decrypt"); + if (input_key_ == nullptr) { s.store_field("input_key", "null"); } else { input_key_->store(s, "input_key"); } + if (data_ == nullptr) { s.store_field("data", "null"); } else { data_->store(s, "data"); } + s.store_class_end(); + } +} + onLiteServerQueryError::onLiteServerQueryError() : id_() , error_() @@ -2005,24 +2647,6 @@ void raw_createQuery::store(td::TlStorerToString &s, const char *field_name) con } } -raw_getAccountAddress::raw_getAccountAddress() - : initital_account_state_() -{} - -raw_getAccountAddress::raw_getAccountAddress(object_ptr &&initital_account_state_) - : initital_account_state_(std::move(initital_account_state_)) -{} - -const std::int32_t raw_getAccountAddress::ID; - -void raw_getAccountAddress::store(td::TlStorerToString &s, const char *field_name) const { - if (!LOG_IS_STRIPPED(ERROR)) { - s.store_class_begin(field_name, "raw_getAccountAddress"); - if (initital_account_state_ == nullptr) { s.store_field("initital_account_state", "null"); } else { initital_account_state_->store(s, "initital_account_state"); } - s.store_class_end(); - } -} - raw_getAccountState::raw_getAccountState() : account_address_() {} @@ -2042,12 +2666,14 @@ void raw_getAccountState::store(td::TlStorerToString &s, const char *field_name) } raw_getTransactions::raw_getTransactions() - : account_address_() + : private_key_() + , account_address_() , from_transaction_id_() {} -raw_getTransactions::raw_getTransactions(object_ptr &&account_address_, object_ptr &&from_transaction_id_) - : account_address_(std::move(account_address_)) +raw_getTransactions::raw_getTransactions(object_ptr &&private_key_, object_ptr &&account_address_, object_ptr &&from_transaction_id_) + : private_key_(std::move(private_key_)) + , account_address_(std::move(account_address_)) , from_transaction_id_(std::move(from_transaction_id_)) {} @@ -2056,6 +2682,7 @@ const std::int32_t raw_getTransactions::ID; void raw_getTransactions::store(td::TlStorerToString &s, const char *field_name) const { if (!LOG_IS_STRIPPED(ERROR)) { s.store_class_begin(field_name, "raw_getTransactions"); + if (private_key_ == nullptr) { s.store_field("private_key", "null"); } else { private_key_->store(s, "private_key"); } if (account_address_ == nullptr) { s.store_field("account_address", "null"); } else { account_address_->store(s, "account_address"); } if (from_transaction_id_ == nullptr) { s.store_field("from_transaction_id", "null"); } else { from_transaction_id_->store(s, "from_transaction_id"); } s.store_class_end(); @@ -2263,141 +2890,6 @@ void sync::store(td::TlStorerToString &s, const char *field_name) const { } } -testGiver_getAccountAddress::testGiver_getAccountAddress() { -} - -const std::int32_t testGiver_getAccountAddress::ID; - -void testGiver_getAccountAddress::store(td::TlStorerToString &s, const char *field_name) const { - if (!LOG_IS_STRIPPED(ERROR)) { - s.store_class_begin(field_name, "testGiver_getAccountAddress"); - s.store_class_end(); - } -} - -testGiver_getAccountState::testGiver_getAccountState() { -} - -const std::int32_t testGiver_getAccountState::ID; - -void testGiver_getAccountState::store(td::TlStorerToString &s, const char *field_name) const { - if (!LOG_IS_STRIPPED(ERROR)) { - s.store_class_begin(field_name, "testGiver_getAccountState"); - s.store_class_end(); - } -} - -testGiver_sendGrams::testGiver_sendGrams() - : destination_() - , seqno_() - , amount_() - , message_() -{} - -testGiver_sendGrams::testGiver_sendGrams(object_ptr &&destination_, std::int32_t seqno_, std::int64_t amount_, std::string const &message_) - : destination_(std::move(destination_)) - , seqno_(seqno_) - , amount_(amount_) - , message_(std::move(message_)) -{} - -const std::int32_t testGiver_sendGrams::ID; - -void testGiver_sendGrams::store(td::TlStorerToString &s, const char *field_name) const { - if (!LOG_IS_STRIPPED(ERROR)) { - s.store_class_begin(field_name, "testGiver_sendGrams"); - if (destination_ == nullptr) { s.store_field("destination", "null"); } else { destination_->store(s, "destination"); } - s.store_field("seqno", seqno_); - s.store_field("amount", amount_); - s.store_bytes_field("message", message_); - s.store_class_end(); - } -} - -testWallet_getAccountAddress::testWallet_getAccountAddress() - : initital_account_state_() -{} - -testWallet_getAccountAddress::testWallet_getAccountAddress(object_ptr &&initital_account_state_) - : initital_account_state_(std::move(initital_account_state_)) -{} - -const std::int32_t testWallet_getAccountAddress::ID; - -void testWallet_getAccountAddress::store(td::TlStorerToString &s, const char *field_name) const { - if (!LOG_IS_STRIPPED(ERROR)) { - s.store_class_begin(field_name, "testWallet_getAccountAddress"); - if (initital_account_state_ == nullptr) { s.store_field("initital_account_state", "null"); } else { initital_account_state_->store(s, "initital_account_state"); } - s.store_class_end(); - } -} - -testWallet_getAccountState::testWallet_getAccountState() - : account_address_() -{} - -testWallet_getAccountState::testWallet_getAccountState(object_ptr &&account_address_) - : account_address_(std::move(account_address_)) -{} - -const std::int32_t testWallet_getAccountState::ID; - -void testWallet_getAccountState::store(td::TlStorerToString &s, const char *field_name) const { - if (!LOG_IS_STRIPPED(ERROR)) { - s.store_class_begin(field_name, "testWallet_getAccountState"); - if (account_address_ == nullptr) { s.store_field("account_address", "null"); } else { account_address_->store(s, "account_address"); } - s.store_class_end(); - } -} - -testWallet_init::testWallet_init() - : private_key_() -{} - -testWallet_init::testWallet_init(object_ptr &&private_key_) - : private_key_(std::move(private_key_)) -{} - -const std::int32_t testWallet_init::ID; - -void testWallet_init::store(td::TlStorerToString &s, const char *field_name) const { - if (!LOG_IS_STRIPPED(ERROR)) { - s.store_class_begin(field_name, "testWallet_init"); - if (private_key_ == nullptr) { s.store_field("private_key", "null"); } else { private_key_->store(s, "private_key"); } - s.store_class_end(); - } -} - -testWallet_sendGrams::testWallet_sendGrams() - : private_key_() - , destination_() - , seqno_() - , amount_() - , message_() -{} - -testWallet_sendGrams::testWallet_sendGrams(object_ptr &&private_key_, object_ptr &&destination_, std::int32_t seqno_, std::int64_t amount_, std::string const &message_) - : private_key_(std::move(private_key_)) - , destination_(std::move(destination_)) - , seqno_(seqno_) - , amount_(amount_) - , message_(std::move(message_)) -{} - -const std::int32_t testWallet_sendGrams::ID; - -void testWallet_sendGrams::store(td::TlStorerToString &s, const char *field_name) const { - if (!LOG_IS_STRIPPED(ERROR)) { - s.store_class_begin(field_name, "testWallet_sendGrams"); - if (private_key_ == nullptr) { s.store_field("private_key", "null"); } else { private_key_->store(s, "private_key"); } - if (destination_ == nullptr) { s.store_field("destination", "null"); } else { destination_->store(s, "destination"); } - s.store_field("seqno", seqno_); - s.store_field("amount", amount_); - s.store_bytes_field("message", message_); - s.store_class_end(); - } -} - unpackAccountAddress::unpackAccountAddress() : account_address_() {} @@ -2416,107 +2908,23 @@ void unpackAccountAddress::store(td::TlStorerToString &s, const char *field_name } } -wallet_getAccountAddress::wallet_getAccountAddress() - : initital_account_state_() +withBlock::withBlock() + : id_() + , function_() {} -wallet_getAccountAddress::wallet_getAccountAddress(object_ptr &&initital_account_state_) - : initital_account_state_(std::move(initital_account_state_)) +withBlock::withBlock(object_ptr &&id_, object_ptr &&function_) + : id_(std::move(id_)) + , function_(std::move(function_)) {} -const std::int32_t wallet_getAccountAddress::ID; +const std::int32_t withBlock::ID; -void wallet_getAccountAddress::store(td::TlStorerToString &s, const char *field_name) const { +void withBlock::store(td::TlStorerToString &s, const char *field_name) const { if (!LOG_IS_STRIPPED(ERROR)) { - s.store_class_begin(field_name, "wallet_getAccountAddress"); - if (initital_account_state_ == nullptr) { s.store_field("initital_account_state", "null"); } else { initital_account_state_->store(s, "initital_account_state"); } - s.store_class_end(); - } -} - -wallet_getAccountState::wallet_getAccountState() - : account_address_() -{} - -wallet_getAccountState::wallet_getAccountState(object_ptr &&account_address_) - : account_address_(std::move(account_address_)) -{} - -const std::int32_t wallet_getAccountState::ID; - -void wallet_getAccountState::store(td::TlStorerToString &s, const char *field_name) const { - if (!LOG_IS_STRIPPED(ERROR)) { - s.store_class_begin(field_name, "wallet_getAccountState"); - if (account_address_ == nullptr) { s.store_field("account_address", "null"); } else { account_address_->store(s, "account_address"); } - s.store_class_end(); - } -} - -wallet_init::wallet_init() - : private_key_() -{} - -wallet_init::wallet_init(object_ptr &&private_key_) - : private_key_(std::move(private_key_)) -{} - -const std::int32_t wallet_init::ID; - -void wallet_init::store(td::TlStorerToString &s, const char *field_name) const { - if (!LOG_IS_STRIPPED(ERROR)) { - s.store_class_begin(field_name, "wallet_init"); - if (private_key_ == nullptr) { s.store_field("private_key", "null"); } else { private_key_->store(s, "private_key"); } - s.store_class_end(); - } -} - -wallet_sendGrams::wallet_sendGrams() - : private_key_() - , destination_() - , seqno_() - , valid_until_() - , amount_() - , message_() -{} - -wallet_sendGrams::wallet_sendGrams(object_ptr &&private_key_, object_ptr &&destination_, std::int32_t seqno_, std::int64_t valid_until_, std::int64_t amount_, std::string const &message_) - : private_key_(std::move(private_key_)) - , destination_(std::move(destination_)) - , seqno_(seqno_) - , valid_until_(valid_until_) - , amount_(amount_) - , message_(std::move(message_)) -{} - -const std::int32_t wallet_sendGrams::ID; - -void wallet_sendGrams::store(td::TlStorerToString &s, const char *field_name) const { - if (!LOG_IS_STRIPPED(ERROR)) { - s.store_class_begin(field_name, "wallet_sendGrams"); - if (private_key_ == nullptr) { s.store_field("private_key", "null"); } else { private_key_->store(s, "private_key"); } - if (destination_ == nullptr) { s.store_field("destination", "null"); } else { destination_->store(s, "destination"); } - s.store_field("seqno", seqno_); - s.store_field("valid_until", valid_until_); - s.store_field("amount", amount_); - s.store_bytes_field("message", message_); - s.store_class_end(); - } -} - -wallet_v3_getAccountAddress::wallet_v3_getAccountAddress() - : initital_account_state_() -{} - -wallet_v3_getAccountAddress::wallet_v3_getAccountAddress(object_ptr &&initital_account_state_) - : initital_account_state_(std::move(initital_account_state_)) -{} - -const std::int32_t wallet_v3_getAccountAddress::ID; - -void wallet_v3_getAccountAddress::store(td::TlStorerToString &s, const char *field_name) const { - if (!LOG_IS_STRIPPED(ERROR)) { - s.store_class_begin(field_name, "wallet_v3_getAccountAddress"); - if (initital_account_state_ == nullptr) { s.store_field("initital_account_state", "null"); } else { initital_account_state_->store(s, "initital_account_state"); } + s.store_class_begin(field_name, "withBlock"); + if (id_ == nullptr) { s.store_field("id", "null"); } else { id_->store(s, "id"); } + if (function_ == nullptr) { s.store_field("function", "null"); } else { function_->store(s, "function"); } s.store_class_end(); } } diff --git a/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api.h b/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api.h index ae90186fea..5247ecddfa 100644 --- a/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api.h +++ b/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api.h @@ -46,6 +46,14 @@ std::string to_string(const object_ptr &value) { class accountAddress; +class accountRevisionList; + +class AccountState; + +class Action; + +class adnlAddress; + class bip39Hints; class config; @@ -60,8 +68,14 @@ class exportedKey; class exportedPemKey; +class exportedUnencryptedKey; + class fees; +class fullAccountState; + +class InitialAccountState; + class InputKey; class key; @@ -78,29 +92,41 @@ class ok; class options; -class sendGramsResult; - class SyncState; class unpackedAccountAddress; class Update; -class generic_AccountState; +class dns_Action; + +class dns_entry; + +class dns_EntryData; + +class dns_resolved; + +class ton_blockId; class internal_transactionId; class liteServer_info; +class msg_Data; + +class msg_dataArray; + +class msg_message; + class options_configInfo; +class options_info; + class query_fees; class query_info; -class raw_accountState; - -class raw_initialAccountState; +class raw_fullAccountState; class raw_message; @@ -114,29 +140,19 @@ class smc_MethodId; class smc_runResult; -class testGiver_accountState; - -class testWallet_accountState; - -class testWallet_initialAccountState; +class ton_blockIdExt; class tvm_cell; +class tvm_list; + class tvm_numberDecimal; class tvm_slice; class tvm_StackEntry; -class uninited_accountState; - -class wallet_accountState; - -class wallet_initialAccountState; - -class wallet_v3_accountState; - -class wallet_v3_initialAccountState; +class tvm_tuple; class Object; @@ -164,6 +180,240 @@ class accountAddress final : public Object { void store(td::TlStorerToString &s, const char *field_name) const final; }; +class accountRevisionList final : public Object { + public: + std::vector revisions_; + + accountRevisionList(); + + explicit accountRevisionList(std::vector &&revisions_); + + static const std::int32_t ID = 120583012; + std::int32_t get_id() const final { + return ID; + } + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + +class AccountState: public Object { + public: +}; + +class raw_accountState final : public AccountState { + public: + std::string code_; + std::string data_; + std::string frozen_hash_; + + raw_accountState(); + + raw_accountState(std::string const &code_, std::string const &data_, std::string const &frozen_hash_); + + static const std::int32_t ID = -531917254; + std::int32_t get_id() const final { + return ID; + } + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + +class testWallet_accountState final : public AccountState { + public: + std::int32_t seqno_; + + testWallet_accountState(); + + explicit testWallet_accountState(std::int32_t seqno_); + + static const std::int32_t ID = -2053909931; + std::int32_t get_id() const final { + return ID; + } + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + +class wallet_accountState final : public AccountState { + public: + std::int32_t seqno_; + + wallet_accountState(); + + explicit wallet_accountState(std::int32_t seqno_); + + static const std::int32_t ID = -390017192; + std::int32_t get_id() const final { + return ID; + } + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + +class wallet_v3_accountState final : public AccountState { + public: + std::int64_t wallet_id_; + std::int32_t seqno_; + + wallet_v3_accountState(); + + wallet_v3_accountState(std::int64_t wallet_id_, std::int32_t seqno_); + + static const std::int32_t ID = -1619351478; + std::int32_t get_id() const final { + return ID; + } + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + +class wallet_highload_v1_accountState final : public AccountState { + public: + std::int64_t wallet_id_; + std::int32_t seqno_; + + wallet_highload_v1_accountState(); + + wallet_highload_v1_accountState(std::int64_t wallet_id_, std::int32_t seqno_); + + static const std::int32_t ID = 1616372956; + std::int32_t get_id() const final { + return ID; + } + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + +class wallet_highload_v2_accountState final : public AccountState { + public: + std::int64_t wallet_id_; + + wallet_highload_v2_accountState(); + + explicit wallet_highload_v2_accountState(std::int64_t wallet_id_); + + static const std::int32_t ID = -1803723441; + std::int32_t get_id() const final { + return ID; + } + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + +class testGiver_accountState final : public AccountState { + public: + std::int32_t seqno_; + + testGiver_accountState(); + + explicit testGiver_accountState(std::int32_t seqno_); + + static const std::int32_t ID = -696813142; + std::int32_t get_id() const final { + return ID; + } + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + +class dns_accountState final : public AccountState { + public: + std::int64_t wallet_id_; + + dns_accountState(); + + explicit dns_accountState(std::int64_t wallet_id_); + + static const std::int32_t ID = 1727715434; + std::int32_t get_id() const final { + return ID; + } + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + +class uninited_accountState final : public AccountState { + public: + std::string frozen_hash_; + + uninited_accountState(); + + explicit uninited_accountState(std::string const &frozen_hash_); + + static const std::int32_t ID = 1522374408; + std::int32_t get_id() const final { + return ID; + } + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + +class Action: public Object { + public: +}; + +class actionNoop final : public Action { + public: + + actionNoop(); + + static const std::int32_t ID = 1135848603; + std::int32_t get_id() const final { + return ID; + } + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + +class actionMsg final : public Action { + public: + std::vector> messages_; + bool allow_send_to_uninited_; + + actionMsg(); + + actionMsg(std::vector> &&messages_, bool allow_send_to_uninited_); + + static const std::int32_t ID = 246839120; + std::int32_t get_id() const final { + return ID; + } + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + +class actionDns final : public Action { + public: + std::vector> actions_; + + actionDns(); + + explicit actionDns(std::vector> &&actions_); + + static const std::int32_t ID = 1193750561; + std::int32_t get_id() const final { + return ID; + } + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + +class adnlAddress final : public Object { + public: + std::string adnl_address_; + + adnlAddress(); + + explicit adnlAddress(std::string const &adnl_address_); + + static const std::int32_t ID = 70358284; + std::int32_t get_id() const final { + return ID; + } + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + class bip39Hints final : public Object { public: std::vector words_; @@ -280,6 +530,22 @@ class exportedPemKey final : public Object { void store(td::TlStorerToString &s, const char *field_name) const final; }; +class exportedUnencryptedKey final : public Object { + public: + td::SecureString data_; + + exportedUnencryptedKey(); + + explicit exportedUnencryptedKey(td::SecureString &&data_); + + static const std::int32_t ID = 730045160; + std::int32_t get_id() const final { + return ID; + } + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + class fees final : public Object { public: std::int64_t in_fwd_fee_; @@ -299,6 +565,160 @@ class fees final : public Object { void store(td::TlStorerToString &s, const char *field_name) const final; }; +class fullAccountState final : public Object { + public: + std::int64_t balance_; + object_ptr last_transaction_id_; + object_ptr block_id_; + std::int64_t sync_utime_; + object_ptr account_state_; + + fullAccountState(); + + fullAccountState(std::int64_t balance_, object_ptr &&last_transaction_id_, object_ptr &&block_id_, std::int64_t sync_utime_, object_ptr &&account_state_); + + static const std::int32_t ID = -686286006; + std::int32_t get_id() const final { + return ID; + } + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + +class InitialAccountState: public Object { + public: +}; + +class raw_initialAccountState final : public InitialAccountState { + public: + std::string code_; + std::string data_; + + raw_initialAccountState(); + + raw_initialAccountState(std::string const &code_, std::string const &data_); + + static const std::int32_t ID = -337945529; + std::int32_t get_id() const final { + return ID; + } + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + +class testGiver_initialAccountState final : public InitialAccountState { + public: + + testGiver_initialAccountState(); + + static const std::int32_t ID = -1448412176; + std::int32_t get_id() const final { + return ID; + } + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + +class testWallet_initialAccountState final : public InitialAccountState { + public: + std::string public_key_; + + testWallet_initialAccountState(); + + explicit testWallet_initialAccountState(std::string const &public_key_); + + static const std::int32_t ID = 819380068; + std::int32_t get_id() const final { + return ID; + } + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + +class wallet_initialAccountState final : public InitialAccountState { + public: + std::string public_key_; + + wallet_initialAccountState(); + + explicit wallet_initialAccountState(std::string const &public_key_); + + static const std::int32_t ID = -1122166790; + std::int32_t get_id() const final { + return ID; + } + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + +class wallet_v3_initialAccountState final : public InitialAccountState { + public: + std::string public_key_; + std::int64_t wallet_id_; + + wallet_v3_initialAccountState(); + + wallet_v3_initialAccountState(std::string const &public_key_, std::int64_t wallet_id_); + + static const std::int32_t ID = -118074048; + std::int32_t get_id() const final { + return ID; + } + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + +class wallet_highload_v1_initialAccountState final : public InitialAccountState { + public: + std::string public_key_; + std::int64_t wallet_id_; + + wallet_highload_v1_initialAccountState(); + + wallet_highload_v1_initialAccountState(std::string const &public_key_, std::int64_t wallet_id_); + + static const std::int32_t ID = -327901626; + std::int32_t get_id() const final { + return ID; + } + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + +class wallet_highload_v2_initialAccountState final : public InitialAccountState { + public: + std::string public_key_; + std::int64_t wallet_id_; + + wallet_highload_v2_initialAccountState(); + + wallet_highload_v2_initialAccountState(std::string const &public_key_, std::int64_t wallet_id_); + + static const std::int32_t ID = 1966373161; + std::int32_t get_id() const final { + return ID; + } + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + +class dns_initialAccountState final : public InitialAccountState { + public: + std::string public_key_; + std::int64_t wallet_id_; + + dns_initialAccountState(); + + dns_initialAccountState(std::string const &public_key_, std::int64_t wallet_id_); + + static const std::int32_t ID = 1842062527; + std::int32_t get_id() const final { + return ID; + } + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + class InputKey: public Object { public: }; @@ -492,23 +912,6 @@ class options final : public Object { void store(td::TlStorerToString &s, const char *field_name) const final; }; -class sendGramsResult final : public Object { - public: - std::int64_t sent_until_; - std::string body_hash_; - - sendGramsResult(); - - sendGramsResult(std::int64_t sent_until_, std::string const &body_hash_); - - static const std::int32_t ID = 426872238; - std::int32_t get_id() const final { - return ID; - } - - void store(td::TlStorerToString &s, const char *field_name) const final; -}; - class SyncState: public Object { public: }; @@ -600,19 +1003,16 @@ class updateSyncState final : public Update { void store(td::TlStorerToString &s, const char *field_name) const final; }; -class generic_AccountState: public Object { +class dns_Action: public Object { public: }; -class generic_accountStateRaw final : public generic_AccountState { +class dns_actionDeleteAll final : public dns_Action { public: - object_ptr account_state_; - generic_accountStateRaw(); + dns_actionDeleteAll(); - explicit generic_accountStateRaw(object_ptr &&account_state_); - - static const std::int32_t ID = -1387096685; + static const std::int32_t ID = 1067356318; std::int32_t get_id() const final { return ID; } @@ -620,15 +1020,16 @@ class generic_accountStateRaw final : public generic_AccountState { void store(td::TlStorerToString &s, const char *field_name) const final; }; -class generic_accountStateTestWallet final : public generic_AccountState { +class dns_actionDelete final : public dns_Action { public: - object_ptr account_state_; + std::string name_; + std::int32_t category_; - generic_accountStateTestWallet(); + dns_actionDelete(); - explicit generic_accountStateTestWallet(object_ptr &&account_state_); + dns_actionDelete(std::string const &name_, std::int32_t category_); - static const std::int32_t ID = -1041955397; + static const std::int32_t ID = 775206882; std::int32_t get_id() const final { return ID; } @@ -636,15 +1037,15 @@ class generic_accountStateTestWallet final : public generic_AccountState { void store(td::TlStorerToString &s, const char *field_name) const final; }; -class generic_accountStateWallet final : public generic_AccountState { +class dns_actionSet final : public dns_Action { public: - object_ptr account_state_; + object_ptr entry_; - generic_accountStateWallet(); + dns_actionSet(); - explicit generic_accountStateWallet(object_ptr &&account_state_); + explicit dns_actionSet(object_ptr &&entry_); - static const std::int32_t ID = 942582925; + static const std::int32_t ID = -1374965309; std::int32_t get_id() const final { return ID; } @@ -652,15 +1053,17 @@ class generic_accountStateWallet final : public generic_AccountState { void store(td::TlStorerToString &s, const char *field_name) const final; }; -class generic_accountStateWalletV3 final : public generic_AccountState { +class dns_entry final : public Object { public: - object_ptr account_state_; + std::string name_; + std::int32_t category_; + object_ptr entry_; - generic_accountStateWalletV3(); + dns_entry(); - explicit generic_accountStateWalletV3(object_ptr &&account_state_); + dns_entry(std::string const &name_, std::int32_t category_, object_ptr &&entry_); - static const std::int32_t ID = -281349583; + static const std::int32_t ID = -1842435400; std::int32_t get_id() const final { return ID; } @@ -668,15 +1071,19 @@ class generic_accountStateWalletV3 final : public generic_AccountState { void store(td::TlStorerToString &s, const char *field_name) const final; }; -class generic_accountStateTestGiver final : public generic_AccountState { +class dns_EntryData: public Object { public: - object_ptr account_state_; +}; - generic_accountStateTestGiver(); +class dns_entryDataUnknown final : public dns_EntryData { + public: + std::string bytes_; - explicit generic_accountStateTestGiver(object_ptr &&account_state_); + dns_entryDataUnknown(); - static const std::int32_t ID = 1134654598; + explicit dns_entryDataUnknown(std::string const &bytes_); + + static const std::int32_t ID = -1285893248; std::int32_t get_id() const final { return ID; } @@ -684,15 +1091,97 @@ class generic_accountStateTestGiver final : public generic_AccountState { void store(td::TlStorerToString &s, const char *field_name) const final; }; -class generic_accountStateUninited final : public generic_AccountState { +class dns_entryDataText final : public dns_EntryData { public: - object_ptr account_state_; + std::string text_; - generic_accountStateUninited(); + dns_entryDataText(); - explicit generic_accountStateUninited(object_ptr &&account_state_); + explicit dns_entryDataText(std::string const &text_); - static const std::int32_t ID = -908702008; + static const std::int32_t ID = -792485614; + std::int32_t get_id() const final { + return ID; + } + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + +class dns_entryDataNextResolver final : public dns_EntryData { + public: + object_ptr resolver_; + + dns_entryDataNextResolver(); + + explicit dns_entryDataNextResolver(object_ptr &&resolver_); + + static const std::int32_t ID = 330382792; + std::int32_t get_id() const final { + return ID; + } + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + +class dns_entryDataSmcAddress final : public dns_EntryData { + public: + object_ptr smc_address_; + + dns_entryDataSmcAddress(); + + explicit dns_entryDataSmcAddress(object_ptr &&smc_address_); + + static const std::int32_t ID = -1759937982; + std::int32_t get_id() const final { + return ID; + } + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + +class dns_entryDataAdnlAddress final : public dns_EntryData { + public: + object_ptr adnl_address_; + + dns_entryDataAdnlAddress(); + + explicit dns_entryDataAdnlAddress(object_ptr &&adnl_address_); + + static const std::int32_t ID = -1114064368; + std::int32_t get_id() const final { + return ID; + } + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + +class dns_resolved final : public Object { + public: + std::vector> entries_; + + dns_resolved(); + + explicit dns_resolved(std::vector> &&entries_); + + static const std::int32_t ID = 2090272150; + std::int32_t get_id() const final { + return ID; + } + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + +class ton_blockId final : public Object { + public: + std::int32_t workchain_; + std::int64_t shard_; + std::int32_t seqno_; + + ton_blockId(); + + ton_blockId(std::int32_t workchain_, std::int64_t shard_, std::int32_t seqno_); + + static const std::int32_t ID = -1185382494; std::int32_t get_id() const final { return ID; } @@ -735,6 +1224,108 @@ class liteServer_info final : public Object { void store(td::TlStorerToString &s, const char *field_name) const final; }; +class msg_Data: public Object { + public: +}; + +class msg_dataRaw final : public msg_Data { + public: + std::string body_; + + msg_dataRaw(); + + explicit msg_dataRaw(std::string const &body_); + + static const std::int32_t ID = 38878511; + std::int32_t get_id() const final { + return ID; + } + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + +class msg_dataText final : public msg_Data { + public: + std::string text_; + + msg_dataText(); + + explicit msg_dataText(std::string const &text_); + + static const std::int32_t ID = -341560688; + std::int32_t get_id() const final { + return ID; + } + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + +class msg_dataDecryptedText final : public msg_Data { + public: + std::string text_; + + msg_dataDecryptedText(); + + explicit msg_dataDecryptedText(std::string const &text_); + + static const std::int32_t ID = -1289133895; + std::int32_t get_id() const final { + return ID; + } + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + +class msg_dataEncryptedText final : public msg_Data { + public: + std::string text_; + + msg_dataEncryptedText(); + + explicit msg_dataEncryptedText(std::string const &text_); + + static const std::int32_t ID = -296612902; + std::int32_t get_id() const final { + return ID; + } + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + +class msg_dataArray final : public Object { + public: + std::vector> elements_; + + msg_dataArray(); + + explicit msg_dataArray(std::vector> &&elements_); + + static const std::int32_t ID = 1248461374; + std::int32_t get_id() const final { + return ID; + } + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + +class msg_message final : public Object { + public: + object_ptr destination_; + std::int64_t amount_; + object_ptr data_; + + msg_message(); + + msg_message(object_ptr &&destination_, std::int64_t amount_, object_ptr &&data_); + + static const std::int32_t ID = 1349943761; + std::int32_t get_id() const final { + return ID; + } + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + class options_configInfo final : public Object { public: std::int64_t default_wallet_id_; @@ -743,7 +1334,23 @@ class options_configInfo final : public Object { explicit options_configInfo(std::int64_t default_wallet_id_); - static const std::int32_t ID = 165216422; + static const std::int32_t ID = 451217371; + std::int32_t get_id() const final { + return ID; + } + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + +class options_info final : public Object { + public: + object_ptr config_info_; + + options_info(); + + explicit options_info(object_ptr &&config_info_); + + static const std::int32_t ID = -64676736; std::int32_t get_id() const final { return ID; } @@ -754,13 +1361,13 @@ class options_configInfo final : public Object { class query_fees final : public Object { public: object_ptr source_fees_; - object_ptr destination_fees_; + std::vector> destination_fees_; query_fees(); - query_fees(object_ptr &&source_fees_, object_ptr &&destination_fees_); + query_fees(object_ptr &&source_fees_, std::vector> &&destination_fees_); - static const std::int32_t ID = 725267759; + static const std::int32_t ID = 1614616510; std::int32_t get_id() const final { return ID; } @@ -786,37 +1393,21 @@ class query_info final : public Object { void store(td::TlStorerToString &s, const char *field_name) const final; }; -class raw_accountState final : public Object { +class raw_fullAccountState final : public Object { public: std::int64_t balance_; std::string code_; std::string data_; object_ptr last_transaction_id_; + object_ptr block_id_; std::string frozen_hash_; std::int64_t sync_utime_; - raw_accountState(); + raw_fullAccountState(); - raw_accountState(std::int64_t balance_, std::string const &code_, std::string const &data_, object_ptr &&last_transaction_id_, std::string const &frozen_hash_, std::int64_t sync_utime_); + raw_fullAccountState(std::int64_t balance_, std::string const &code_, std::string const &data_, object_ptr &&last_transaction_id_, object_ptr &&block_id_, std::string const &frozen_hash_, std::int64_t sync_utime_); - static const std::int32_t ID = 1205935434; - std::int32_t get_id() const final { - return ID; - } - - void store(td::TlStorerToString &s, const char *field_name) const final; -}; - -class raw_initialAccountState final : public Object { - public: - std::string code_; - std::string data_; - - raw_initialAccountState(); - - raw_initialAccountState(std::string const &code_, std::string const &data_); - - static const std::int32_t ID = 777456197; + static const std::int32_t ID = -1465398385; std::int32_t get_id() const final { return ID; } @@ -833,13 +1424,13 @@ class raw_message final : public Object { std::int64_t ihr_fee_; std::int64_t created_lt_; std::string body_hash_; - std::string message_; + object_ptr msg_data_; raw_message(); - raw_message(std::string const &source_, std::string const &destination_, std::int64_t value_, std::int64_t fwd_fee_, std::int64_t ihr_fee_, std::int64_t created_lt_, std::string const &body_hash_, std::string const &message_); + raw_message(std::string const &source_, std::string const &destination_, std::int64_t value_, std::int64_t fwd_fee_, std::int64_t ihr_fee_, std::int64_t created_lt_, std::string const &body_hash_, object_ptr &&msg_data_); - static const std::int32_t ID = -906281442; + static const std::int32_t ID = -32842388; std::int32_t get_id() const final { return ID; } @@ -957,53 +1548,19 @@ class smc_runResult final : public Object { void store(td::TlStorerToString &s, const char *field_name) const final; }; -class testGiver_accountState final : public Object { +class ton_blockIdExt final : public Object { public: - std::int64_t balance_; + std::int32_t workchain_; + std::int64_t shard_; std::int32_t seqno_; - object_ptr last_transaction_id_; - std::int64_t sync_utime_; + std::string root_hash_; + std::string file_hash_; - testGiver_accountState(); + ton_blockIdExt(); - testGiver_accountState(std::int64_t balance_, std::int32_t seqno_, object_ptr &&last_transaction_id_, std::int64_t sync_utime_); + ton_blockIdExt(std::int32_t workchain_, std::int64_t shard_, std::int32_t seqno_, std::string const &root_hash_, std::string const &file_hash_); - static const std::int32_t ID = 860930426; - std::int32_t get_id() const final { - return ID; - } - - void store(td::TlStorerToString &s, const char *field_name) const final; -}; - -class testWallet_accountState final : public Object { - public: - std::int64_t balance_; - std::int32_t seqno_; - object_ptr last_transaction_id_; - std::int64_t sync_utime_; - - testWallet_accountState(); - - testWallet_accountState(std::int64_t balance_, std::int32_t seqno_, object_ptr &&last_transaction_id_, std::int64_t sync_utime_); - - static const std::int32_t ID = 305698744; - std::int32_t get_id() const final { - return ID; - } - - void store(td::TlStorerToString &s, const char *field_name) const final; -}; - -class testWallet_initialAccountState final : public Object { - public: - std::string public_key_; - - testWallet_initialAccountState(); - - explicit testWallet_initialAccountState(std::string const &public_key_); - - static const std::int32_t ID = -1231516227; + static const std::int32_t ID = 2031156378; std::int32_t get_id() const final { return ID; } @@ -1019,7 +1576,23 @@ class tvm_cell final : public Object { explicit tvm_cell(std::string const &bytes_); - static const std::int32_t ID = -859530316; + static const std::int32_t ID = -413424735; + std::int32_t get_id() const final { + return ID; + } + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + +class tvm_list final : public Object { + public: + std::vector> elements_; + + tvm_list(); + + explicit tvm_list(std::vector> &&elements_); + + static const std::int32_t ID = 1270320392; std::int32_t get_id() const final { return ID; } @@ -1051,7 +1624,7 @@ class tvm_slice final : public Object { explicit tvm_slice(std::string const &bytes_); - static const std::int32_t ID = -1069968387; + static const std::int32_t ID = 537299687; std::int32_t get_id() const final { return ID; } @@ -1111,6 +1684,38 @@ class tvm_stackEntryNumber final : public tvm_StackEntry { void store(td::TlStorerToString &s, const char *field_name) const final; }; +class tvm_stackEntryTuple final : public tvm_StackEntry { + public: + object_ptr tuple_; + + tvm_stackEntryTuple(); + + explicit tvm_stackEntryTuple(object_ptr &&tuple_); + + static const std::int32_t ID = -157391908; + std::int32_t get_id() const final { + return ID; + } + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + +class tvm_stackEntryList final : public tvm_StackEntry { + public: + object_ptr list_; + + tvm_stackEntryList(); + + explicit tvm_stackEntryList(object_ptr &&list_); + + static const std::int32_t ID = -1186714229; + std::int32_t get_id() const final { + return ID; + } + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + class tvm_stackEntryUnsupported final : public tvm_StackEntry { public: @@ -1124,90 +1729,15 @@ class tvm_stackEntryUnsupported final : public tvm_StackEntry { void store(td::TlStorerToString &s, const char *field_name) const final; }; -class uninited_accountState final : public Object { +class tvm_tuple final : public Object { public: - std::int64_t balance_; - object_ptr last_transaction_id_; - std::string frozen_hash_; - std::int64_t sync_utime_; + std::vector> elements_; - uninited_accountState(); + tvm_tuple(); - uninited_accountState(std::int64_t balance_, object_ptr &&last_transaction_id_, std::string const &frozen_hash_, std::int64_t sync_utime_); + explicit tvm_tuple(std::vector> &&elements_); - static const std::int32_t ID = -918880075; - std::int32_t get_id() const final { - return ID; - } - - void store(td::TlStorerToString &s, const char *field_name) const final; -}; - -class wallet_accountState final : public Object { - public: - std::int64_t balance_; - std::int32_t seqno_; - object_ptr last_transaction_id_; - std::int64_t sync_utime_; - - wallet_accountState(); - - wallet_accountState(std::int64_t balance_, std::int32_t seqno_, object_ptr &&last_transaction_id_, std::int64_t sync_utime_); - - static const std::int32_t ID = -1919815977; - std::int32_t get_id() const final { - return ID; - } - - void store(td::TlStorerToString &s, const char *field_name) const final; -}; - -class wallet_initialAccountState final : public Object { - public: - std::string public_key_; - - wallet_initialAccountState(); - - explicit wallet_initialAccountState(std::string const &public_key_); - - static const std::int32_t ID = -1079249978; - std::int32_t get_id() const final { - return ID; - } - - void store(td::TlStorerToString &s, const char *field_name) const final; -}; - -class wallet_v3_accountState final : public Object { - public: - std::int64_t balance_; - std::int64_t wallet_id_; - std::int32_t seqno_; - object_ptr last_transaction_id_; - std::int64_t sync_utime_; - - wallet_v3_accountState(); - - wallet_v3_accountState(std::int64_t balance_, std::int64_t wallet_id_, std::int32_t seqno_, object_ptr &&last_transaction_id_, std::int64_t sync_utime_); - - static const std::int32_t ID = 1977698154; - std::int32_t get_id() const final { - return ID; - } - - void store(td::TlStorerToString &s, const char *field_name) const final; -}; - -class wallet_v3_initialAccountState final : public Object { - public: - std::string public_key_; - std::int64_t wallet_id_; - - wallet_v3_initialAccountState(); - - wallet_v3_initialAccountState(std::string const &public_key_, std::int64_t wallet_id_); - - static const std::int32_t ID = 283460879; + static const std::int32_t ID = -1363953053; std::int32_t get_id() const final { return ID; } @@ -1288,6 +1818,27 @@ class createNewKey final : public Function { void store(td::TlStorerToString &s, const char *field_name) const final; }; +class createQuery final : public Function { + public: + object_ptr private_key_; + object_ptr address_; + std::int32_t timeout_; + object_ptr action_; + + createQuery(); + + createQuery(object_ptr &&private_key_, object_ptr &&address_, std::int32_t timeout_, object_ptr &&action_); + + static const std::int32_t ID = -1316835098; + std::int32_t get_id() const final { + return ID; + } + + using ReturnType = object_ptr; + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + class decrypt final : public Function { public: td::SecureString encrypted_data_; @@ -1340,6 +1891,27 @@ class deleteKey final : public Function { void store(td::TlStorerToString &s, const char *field_name) const final; }; +class dns_resolve final : public Function { + public: + object_ptr account_address_; + std::string name_; + std::int32_t category_; + std::int32_t ttl_; + + dns_resolve(); + + dns_resolve(object_ptr &&account_address_, std::string const &name_, std::int32_t category_, std::int32_t ttl_); + + static const std::int32_t ID = -149238065; + std::int32_t get_id() const final { + return ID; + } + + using ReturnType = object_ptr; + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + class encrypt final : public Function { public: td::SecureString decrypted_data_; @@ -1415,68 +1987,57 @@ class exportPemKey final : public Function { void store(td::TlStorerToString &s, const char *field_name) const final; }; -class generic_createSendGramsQuery final : public Function { +class exportUnencryptedKey final : public Function { public: - object_ptr private_key_; - object_ptr source_; - object_ptr destination_; - std::int64_t amount_; - std::int32_t timeout_; - bool allow_send_to_uninited_; - std::string message_; + object_ptr input_key_; - generic_createSendGramsQuery(); + exportUnencryptedKey(); - generic_createSendGramsQuery(object_ptr &&private_key_, object_ptr &&source_, object_ptr &&destination_, std::int64_t amount_, std::int32_t timeout_, bool allow_send_to_uninited_, std::string const &message_); + explicit exportUnencryptedKey(object_ptr &&input_key_); - static const std::int32_t ID = 208206338; + static const std::int32_t ID = -634665152; std::int32_t get_id() const final { return ID; } - using ReturnType = object_ptr; + using ReturnType = object_ptr; void store(td::TlStorerToString &s, const char *field_name) const final; }; -class generic_getAccountState final : public Function { +class getAccountAddress final : public Function { + public: + object_ptr initial_account_state_; + std::int32_t revision_; + + getAccountAddress(); + + getAccountAddress(object_ptr &&initial_account_state_, std::int32_t revision_); + + static const std::int32_t ID = -1159101819; + std::int32_t get_id() const final { + return ID; + } + + using ReturnType = object_ptr; + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + +class getAccountState final : public Function { public: object_ptr account_address_; - generic_getAccountState(); + getAccountState(); - explicit generic_getAccountState(object_ptr &&account_address_); + explicit getAccountState(object_ptr &&account_address_); - static const std::int32_t ID = -657000446; + static const std::int32_t ID = -2116357050; std::int32_t get_id() const final { return ID; } - using ReturnType = object_ptr; - - void store(td::TlStorerToString &s, const char *field_name) const final; -}; - -class generic_sendGrams final : public Function { - public: - object_ptr private_key_; - object_ptr source_; - object_ptr destination_; - std::int64_t amount_; - std::int32_t timeout_; - bool allow_send_to_uninited_; - std::string message_; - - generic_sendGrams(); - - generic_sendGrams(object_ptr &&private_key_, object_ptr &&source_, object_ptr &&destination_, std::int64_t amount_, std::int32_t timeout_, bool allow_send_to_uninited_, std::string const &message_); - - static const std::int32_t ID = -553513162; - std::int32_t get_id() const final { - return ID; - } - - using ReturnType = object_ptr; + using ReturnType = object_ptr; void store(td::TlStorerToString &s, const char *field_name) const final; }; @@ -1562,6 +2123,24 @@ class getLogVerbosityLevel final : public Function { void store(td::TlStorerToString &s, const char *field_name) const final; }; +class guessAccountRevision final : public Function { + public: + object_ptr initial_account_state_; + + guessAccountRevision(); + + explicit guessAccountRevision(object_ptr &&initial_account_state_); + + static const std::int32_t ID = 1463344293; + std::int32_t get_id() const final { + return ID; + } + + using ReturnType = object_ptr; + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + class importEncryptedKey final : public Function { public: td::SecureString local_password_; @@ -1622,6 +2201,25 @@ class importPemKey final : public Function { void store(td::TlStorerToString &s, const char *field_name) const final; }; +class importUnencryptedKey final : public Function { + public: + td::SecureString local_password_; + object_ptr exported_unencrypted_key_; + + importUnencryptedKey(); + + importUnencryptedKey(td::SecureString &&local_password_, object_ptr &&exported_unencrypted_key_); + + static const std::int32_t ID = -1184671467; + std::int32_t get_id() const final { + return ID; + } + + using ReturnType = object_ptr; + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + class init final : public Function { public: object_ptr options_; @@ -1630,12 +2228,12 @@ class init final : public Function { explicit init(object_ptr &&options_); - static const std::int32_t ID = -2014661877; + static const std::int32_t ID = -1000594762; std::int32_t get_id() const final { return ID; } - using ReturnType = object_ptr; + using ReturnType = object_ptr; void store(td::TlStorerToString &s, const char *field_name) const final; }; @@ -1675,6 +2273,25 @@ class liteServer_getInfo final : public Function { void store(td::TlStorerToString &s, const char *field_name) const final; }; +class msg_decrypt final : public Function { + public: + object_ptr input_key_; + object_ptr data_; + + msg_decrypt(); + + msg_decrypt(object_ptr &&input_key_, object_ptr &&data_); + + static const std::int32_t ID = 1131086633; + std::int32_t get_id() const final { + return ID; + } + + using ReturnType = object_ptr; + + void store(td::TlStorerToString &s, const char *field_name) const final; +}; + class onLiteServerQueryError final : public Function { public: std::int64_t id_; @@ -1721,12 +2338,12 @@ class options_setConfig final : public Function { explicit options_setConfig(object_ptr &&config_); - static const std::int32_t ID = 646497241; + static const std::int32_t ID = 1870064579; std::int32_t get_id() const final { return ID; } - using ReturnType = object_ptr; + using ReturnType = object_ptr; void store(td::TlStorerToString &s, const char *field_name) const final; }; @@ -1881,24 +2498,6 @@ class raw_createQuery final : public Function { void store(td::TlStorerToString &s, const char *field_name) const final; }; -class raw_getAccountAddress final : public Function { - public: - object_ptr initital_account_state_; - - raw_getAccountAddress(); - - explicit raw_getAccountAddress(object_ptr &&initital_account_state_); - - static const std::int32_t ID = -521283849; - std::int32_t get_id() const final { - return ID; - } - - using ReturnType = object_ptr; - - void store(td::TlStorerToString &s, const char *field_name) const final; -}; - class raw_getAccountState final : public Function { public: object_ptr account_address_; @@ -1907,26 +2506,27 @@ class raw_getAccountState final : public Function { explicit raw_getAccountState(object_ptr &&account_address_); - static const std::int32_t ID = 663706721; + static const std::int32_t ID = -1327847118; std::int32_t get_id() const final { return ID; } - using ReturnType = object_ptr; + using ReturnType = object_ptr; void store(td::TlStorerToString &s, const char *field_name) const final; }; class raw_getTransactions final : public Function { public: + object_ptr private_key_; object_ptr account_address_; object_ptr from_transaction_id_; raw_getTransactions(); - raw_getTransactions(object_ptr &&account_address_, object_ptr &&from_transaction_id_); + raw_getTransactions(object_ptr &&private_key_, object_ptr &&account_address_, object_ptr &&from_transaction_id_); - static const std::int32_t ID = 935377269; + static const std::int32_t ID = 1029612317; std::int32_t get_id() const final { return ID; } @@ -2124,139 +2724,12 @@ class sync final : public Function { sync(); - static const std::int32_t ID = -1617065525; + static const std::int32_t ID = -1875977070; std::int32_t get_id() const final { return ID; } - using ReturnType = object_ptr; - - void store(td::TlStorerToString &s, const char *field_name) const final; -}; - -class testGiver_getAccountAddress final : public Function { - public: - - testGiver_getAccountAddress(); - - static const std::int32_t ID = -540100768; - std::int32_t get_id() const final { - return ID; - } - - using ReturnType = object_ptr; - - void store(td::TlStorerToString &s, const char *field_name) const final; -}; - -class testGiver_getAccountState final : public Function { - public: - - testGiver_getAccountState(); - - static const std::int32_t ID = 267738275; - std::int32_t get_id() const final { - return ID; - } - - using ReturnType = object_ptr; - - void store(td::TlStorerToString &s, const char *field_name) const final; -}; - -class testGiver_sendGrams final : public Function { - public: - object_ptr destination_; - std::int32_t seqno_; - std::int64_t amount_; - std::string message_; - - testGiver_sendGrams(); - - testGiver_sendGrams(object_ptr &&destination_, std::int32_t seqno_, std::int64_t amount_, std::string const &message_); - - static const std::int32_t ID = -1785750375; - std::int32_t get_id() const final { - return ID; - } - - using ReturnType = object_ptr; - - void store(td::TlStorerToString &s, const char *field_name) const final; -}; - -class testWallet_getAccountAddress final : public Function { - public: - object_ptr initital_account_state_; - - testWallet_getAccountAddress(); - - explicit testWallet_getAccountAddress(object_ptr &&initital_account_state_); - - static const std::int32_t ID = -1557748223; - std::int32_t get_id() const final { - return ID; - } - - using ReturnType = object_ptr; - - void store(td::TlStorerToString &s, const char *field_name) const final; -}; - -class testWallet_getAccountState final : public Function { - public: - object_ptr account_address_; - - testWallet_getAccountState(); - - explicit testWallet_getAccountState(object_ptr &&account_address_); - - static const std::int32_t ID = 654082364; - std::int32_t get_id() const final { - return ID; - } - - using ReturnType = object_ptr; - - void store(td::TlStorerToString &s, const char *field_name) const final; -}; - -class testWallet_init final : public Function { - public: - object_ptr private_key_; - - testWallet_init(); - - explicit testWallet_init(object_ptr &&private_key_); - - static const std::int32_t ID = -1417409140; - std::int32_t get_id() const final { - return ID; - } - - using ReturnType = object_ptr; - - void store(td::TlStorerToString &s, const char *field_name) const final; -}; - -class testWallet_sendGrams final : public Function { - public: - object_ptr private_key_; - object_ptr destination_; - std::int32_t seqno_; - std::int64_t amount_; - std::string message_; - - testWallet_sendGrams(); - - testWallet_sendGrams(object_ptr &&private_key_, object_ptr &&destination_, std::int32_t seqno_, std::int64_t amount_, std::string const &message_); - - static const std::int32_t ID = 573748322; - std::int32_t get_id() const final { - return ID; - } - - using ReturnType = object_ptr; + using ReturnType = object_ptr; void store(td::TlStorerToString &s, const char *field_name) const final; }; @@ -2279,97 +2752,21 @@ class unpackAccountAddress final : public Function { void store(td::TlStorerToString &s, const char *field_name) const final; }; -class wallet_getAccountAddress final : public Function { +class withBlock final : public Function { public: - object_ptr initital_account_state_; + object_ptr id_; + object_ptr function_; - wallet_getAccountAddress(); + withBlock(); - explicit wallet_getAccountAddress(object_ptr &&initital_account_state_); + withBlock(object_ptr &&id_, object_ptr &&function_); - static const std::int32_t ID = -1004103180; + static const std::int32_t ID = -789093723; std::int32_t get_id() const final { return ID; } - using ReturnType = object_ptr; - - void store(td::TlStorerToString &s, const char *field_name) const final; -}; - -class wallet_getAccountState final : public Function { - public: - object_ptr account_address_; - - wallet_getAccountState(); - - explicit wallet_getAccountState(object_ptr &&account_address_); - - static const std::int32_t ID = 462294850; - std::int32_t get_id() const final { - return ID; - } - - using ReturnType = object_ptr; - - void store(td::TlStorerToString &s, const char *field_name) const final; -}; - -class wallet_init final : public Function { - public: - object_ptr private_key_; - - wallet_init(); - - explicit wallet_init(object_ptr &&private_key_); - - static const std::int32_t ID = -395706309; - std::int32_t get_id() const final { - return ID; - } - - using ReturnType = object_ptr; - - void store(td::TlStorerToString &s, const char *field_name) const final; -}; - -class wallet_sendGrams final : public Function { - public: - object_ptr private_key_; - object_ptr destination_; - std::int32_t seqno_; - std::int64_t valid_until_; - std::int64_t amount_; - std::string message_; - - wallet_sendGrams(); - - wallet_sendGrams(object_ptr &&private_key_, object_ptr &&destination_, std::int32_t seqno_, std::int64_t valid_until_, std::int64_t amount_, std::string const &message_); - - static const std::int32_t ID = 297317621; - std::int32_t get_id() const final { - return ID; - } - - using ReturnType = object_ptr; - - void store(td::TlStorerToString &s, const char *field_name) const final; -}; - -class wallet_v3_getAccountAddress final : public Function { - public: - object_ptr initital_account_state_; - - wallet_v3_getAccountAddress(); - - explicit wallet_v3_getAccountAddress(object_ptr &&initital_account_state_); - - static const std::int32_t ID = 1011655671; - std::int32_t get_id() const final { - return ID; - } - - using ReturnType = object_ptr; + using ReturnType = object_ptr; void store(td::TlStorerToString &s, const char *field_name) const final; }; diff --git a/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api.hpp b/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api.hpp index f82b020a0d..ad2ac76a43 100644 --- a/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api.hpp +++ b/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api.hpp @@ -17,6 +17,48 @@ bool downcast_call(Object &obj, const T &func) { case accountAddress::ID: func(static_cast(obj)); return true; + case accountRevisionList::ID: + func(static_cast(obj)); + return true; + case raw_accountState::ID: + func(static_cast(obj)); + return true; + case testWallet_accountState::ID: + func(static_cast(obj)); + return true; + case wallet_accountState::ID: + func(static_cast(obj)); + return true; + case wallet_v3_accountState::ID: + func(static_cast(obj)); + return true; + case wallet_highload_v1_accountState::ID: + func(static_cast(obj)); + return true; + case wallet_highload_v2_accountState::ID: + func(static_cast(obj)); + return true; + case testGiver_accountState::ID: + func(static_cast(obj)); + return true; + case dns_accountState::ID: + func(static_cast(obj)); + return true; + case uninited_accountState::ID: + func(static_cast(obj)); + return true; + case actionNoop::ID: + func(static_cast(obj)); + return true; + case actionMsg::ID: + func(static_cast(obj)); + return true; + case actionDns::ID: + func(static_cast(obj)); + return true; + case adnlAddress::ID: + func(static_cast(obj)); + return true; case bip39Hints::ID: func(static_cast(obj)); return true; @@ -38,9 +80,39 @@ bool downcast_call(Object &obj, const T &func) { case exportedPemKey::ID: func(static_cast(obj)); return true; + case exportedUnencryptedKey::ID: + func(static_cast(obj)); + return true; case fees::ID: func(static_cast(obj)); return true; + case fullAccountState::ID: + func(static_cast(obj)); + return true; + case raw_initialAccountState::ID: + func(static_cast(obj)); + return true; + case testGiver_initialAccountState::ID: + func(static_cast(obj)); + return true; + case testWallet_initialAccountState::ID: + func(static_cast(obj)); + return true; + case wallet_initialAccountState::ID: + func(static_cast(obj)); + return true; + case wallet_v3_initialAccountState::ID: + func(static_cast(obj)); + return true; + case wallet_highload_v1_initialAccountState::ID: + func(static_cast(obj)); + return true; + case wallet_highload_v2_initialAccountState::ID: + func(static_cast(obj)); + return true; + case dns_initialAccountState::ID: + func(static_cast(obj)); + return true; case inputKeyRegular::ID: func(static_cast(obj)); return true; @@ -77,9 +149,6 @@ bool downcast_call(Object &obj, const T &func) { case options::ID: func(static_cast(obj)); return true; - case sendGramsResult::ID: - func(static_cast(obj)); - return true; case syncStateDone::ID: func(static_cast(obj)); return true; @@ -95,23 +164,38 @@ bool downcast_call(Object &obj, const T &func) { case updateSyncState::ID: func(static_cast(obj)); return true; - case generic_accountStateRaw::ID: - func(static_cast(obj)); + case dns_actionDeleteAll::ID: + func(static_cast(obj)); return true; - case generic_accountStateTestWallet::ID: - func(static_cast(obj)); + case dns_actionDelete::ID: + func(static_cast(obj)); return true; - case generic_accountStateWallet::ID: - func(static_cast(obj)); + case dns_actionSet::ID: + func(static_cast(obj)); return true; - case generic_accountStateWalletV3::ID: - func(static_cast(obj)); + case dns_entry::ID: + func(static_cast(obj)); return true; - case generic_accountStateTestGiver::ID: - func(static_cast(obj)); + case dns_entryDataUnknown::ID: + func(static_cast(obj)); return true; - case generic_accountStateUninited::ID: - func(static_cast(obj)); + case dns_entryDataText::ID: + func(static_cast(obj)); + return true; + case dns_entryDataNextResolver::ID: + func(static_cast(obj)); + return true; + case dns_entryDataSmcAddress::ID: + func(static_cast(obj)); + return true; + case dns_entryDataAdnlAddress::ID: + func(static_cast(obj)); + return true; + case dns_resolved::ID: + func(static_cast(obj)); + return true; + case ton_blockId::ID: + func(static_cast(obj)); return true; case internal_transactionId::ID: func(static_cast(obj)); @@ -119,20 +203,38 @@ bool downcast_call(Object &obj, const T &func) { case liteServer_info::ID: func(static_cast(obj)); return true; + case msg_dataRaw::ID: + func(static_cast(obj)); + return true; + case msg_dataText::ID: + func(static_cast(obj)); + return true; + case msg_dataDecryptedText::ID: + func(static_cast(obj)); + return true; + case msg_dataEncryptedText::ID: + func(static_cast(obj)); + return true; + case msg_dataArray::ID: + func(static_cast(obj)); + return true; + case msg_message::ID: + func(static_cast(obj)); + return true; case options_configInfo::ID: func(static_cast(obj)); return true; + case options_info::ID: + func(static_cast(obj)); + return true; case query_fees::ID: func(static_cast(obj)); return true; case query_info::ID: func(static_cast(obj)); return true; - case raw_accountState::ID: - func(static_cast(obj)); - return true; - case raw_initialAccountState::ID: - func(static_cast(obj)); + case raw_fullAccountState::ID: + func(static_cast(obj)); return true; case raw_message::ID: func(static_cast(obj)); @@ -155,18 +257,15 @@ bool downcast_call(Object &obj, const T &func) { case smc_runResult::ID: func(static_cast(obj)); return true; - case testGiver_accountState::ID: - func(static_cast(obj)); - return true; - case testWallet_accountState::ID: - func(static_cast(obj)); - return true; - case testWallet_initialAccountState::ID: - func(static_cast(obj)); + case ton_blockIdExt::ID: + func(static_cast(obj)); return true; case tvm_cell::ID: func(static_cast(obj)); return true; + case tvm_list::ID: + func(static_cast(obj)); + return true; case tvm_numberDecimal::ID: func(static_cast(obj)); return true; @@ -182,23 +281,17 @@ bool downcast_call(Object &obj, const T &func) { case tvm_stackEntryNumber::ID: func(static_cast(obj)); return true; + case tvm_stackEntryTuple::ID: + func(static_cast(obj)); + return true; + case tvm_stackEntryList::ID: + func(static_cast(obj)); + return true; case tvm_stackEntryUnsupported::ID: func(static_cast(obj)); return true; - case uninited_accountState::ID: - func(static_cast(obj)); - return true; - case wallet_accountState::ID: - func(static_cast(obj)); - return true; - case wallet_initialAccountState::ID: - func(static_cast(obj)); - return true; - case wallet_v3_accountState::ID: - func(static_cast(obj)); - return true; - case wallet_v3_initialAccountState::ID: - func(static_cast(obj)); + case tvm_tuple::ID: + func(static_cast(obj)); return true; default: return false; @@ -226,6 +319,9 @@ bool downcast_call(Function &obj, const T &func) { case createNewKey::ID: func(static_cast(obj)); return true; + case createQuery::ID: + func(static_cast(obj)); + return true; case decrypt::ID: func(static_cast(obj)); return true; @@ -235,6 +331,9 @@ bool downcast_call(Function &obj, const T &func) { case deleteKey::ID: func(static_cast(obj)); return true; + case dns_resolve::ID: + func(static_cast(obj)); + return true; case encrypt::ID: func(static_cast(obj)); return true; @@ -247,14 +346,14 @@ bool downcast_call(Function &obj, const T &func) { case exportPemKey::ID: func(static_cast(obj)); return true; - case generic_createSendGramsQuery::ID: - func(static_cast(obj)); + case exportUnencryptedKey::ID: + func(static_cast(obj)); return true; - case generic_getAccountState::ID: - func(static_cast(obj)); + case getAccountAddress::ID: + func(static_cast(obj)); return true; - case generic_sendGrams::ID: - func(static_cast(obj)); + case getAccountState::ID: + func(static_cast(obj)); return true; case getBip39Hints::ID: func(static_cast(obj)); @@ -271,6 +370,9 @@ bool downcast_call(Function &obj, const T &func) { case getLogVerbosityLevel::ID: func(static_cast(obj)); return true; + case guessAccountRevision::ID: + func(static_cast(obj)); + return true; case importEncryptedKey::ID: func(static_cast(obj)); return true; @@ -280,6 +382,9 @@ bool downcast_call(Function &obj, const T &func) { case importPemKey::ID: func(static_cast(obj)); return true; + case importUnencryptedKey::ID: + func(static_cast(obj)); + return true; case init::ID: func(static_cast(obj)); return true; @@ -289,6 +394,9 @@ bool downcast_call(Function &obj, const T &func) { case liteServer_getInfo::ID: func(static_cast(obj)); return true; + case msg_decrypt::ID: + func(static_cast(obj)); + return true; case onLiteServerQueryError::ID: func(static_cast(obj)); return true; @@ -322,9 +430,6 @@ bool downcast_call(Function &obj, const T &func) { case raw_createQuery::ID: func(static_cast(obj)); return true; - case raw_getAccountAddress::ID: - func(static_cast(obj)); - return true; case raw_getAccountState::ID: func(static_cast(obj)); return true; @@ -364,44 +469,113 @@ bool downcast_call(Function &obj, const T &func) { case sync::ID: func(static_cast(obj)); return true; - case testGiver_getAccountAddress::ID: - func(static_cast(obj)); - return true; - case testGiver_getAccountState::ID: - func(static_cast(obj)); - return true; - case testGiver_sendGrams::ID: - func(static_cast(obj)); - return true; - case testWallet_getAccountAddress::ID: - func(static_cast(obj)); - return true; - case testWallet_getAccountState::ID: - func(static_cast(obj)); - return true; - case testWallet_init::ID: - func(static_cast(obj)); - return true; - case testWallet_sendGrams::ID: - func(static_cast(obj)); - return true; case unpackAccountAddress::ID: func(static_cast(obj)); return true; - case wallet_getAccountAddress::ID: - func(static_cast(obj)); + case withBlock::ID: + func(static_cast(obj)); return true; - case wallet_getAccountState::ID: - func(static_cast(obj)); + default: + return false; + } +} + +/** + * Calls specified function object with the specified object downcasted to the most-derived type. + * \param[in] obj Object to pass as an argument to the function object. + * \param[in] func Function object to which the object will be passed. + * \returns whether function object call has happened. Should always return true for correct parameters. + */ +template +bool downcast_call(AccountState &obj, const T &func) { + switch (obj.get_id()) { + case raw_accountState::ID: + func(static_cast(obj)); return true; - case wallet_init::ID: - func(static_cast(obj)); + case testWallet_accountState::ID: + func(static_cast(obj)); return true; - case wallet_sendGrams::ID: - func(static_cast(obj)); + case wallet_accountState::ID: + func(static_cast(obj)); return true; - case wallet_v3_getAccountAddress::ID: - func(static_cast(obj)); + case wallet_v3_accountState::ID: + func(static_cast(obj)); + return true; + case wallet_highload_v1_accountState::ID: + func(static_cast(obj)); + return true; + case wallet_highload_v2_accountState::ID: + func(static_cast(obj)); + return true; + case testGiver_accountState::ID: + func(static_cast(obj)); + return true; + case dns_accountState::ID: + func(static_cast(obj)); + return true; + case uninited_accountState::ID: + func(static_cast(obj)); + return true; + default: + return false; + } +} + +/** + * Calls specified function object with the specified object downcasted to the most-derived type. + * \param[in] obj Object to pass as an argument to the function object. + * \param[in] func Function object to which the object will be passed. + * \returns whether function object call has happened. Should always return true for correct parameters. + */ +template +bool downcast_call(Action &obj, const T &func) { + switch (obj.get_id()) { + case actionNoop::ID: + func(static_cast(obj)); + return true; + case actionMsg::ID: + func(static_cast(obj)); + return true; + case actionDns::ID: + func(static_cast(obj)); + return true; + default: + return false; + } +} + +/** + * Calls specified function object with the specified object downcasted to the most-derived type. + * \param[in] obj Object to pass as an argument to the function object. + * \param[in] func Function object to which the object will be passed. + * \returns whether function object call has happened. Should always return true for correct parameters. + */ +template +bool downcast_call(InitialAccountState &obj, const T &func) { + switch (obj.get_id()) { + case raw_initialAccountState::ID: + func(static_cast(obj)); + return true; + case testGiver_initialAccountState::ID: + func(static_cast(obj)); + return true; + case testWallet_initialAccountState::ID: + func(static_cast(obj)); + return true; + case wallet_initialAccountState::ID: + func(static_cast(obj)); + return true; + case wallet_v3_initialAccountState::ID: + func(static_cast(obj)); + return true; + case wallet_highload_v1_initialAccountState::ID: + func(static_cast(obj)); + return true; + case wallet_highload_v2_initialAccountState::ID: + func(static_cast(obj)); + return true; + case dns_initialAccountState::ID: + func(static_cast(obj)); return true; default: return false; @@ -518,25 +692,71 @@ bool downcast_call(Update &obj, const T &func) { * \returns whether function object call has happened. Should always return true for correct parameters. */ template -bool downcast_call(generic_AccountState &obj, const T &func) { +bool downcast_call(dns_Action &obj, const T &func) { switch (obj.get_id()) { - case generic_accountStateRaw::ID: - func(static_cast(obj)); + case dns_actionDeleteAll::ID: + func(static_cast(obj)); return true; - case generic_accountStateTestWallet::ID: - func(static_cast(obj)); + case dns_actionDelete::ID: + func(static_cast(obj)); return true; - case generic_accountStateWallet::ID: - func(static_cast(obj)); + case dns_actionSet::ID: + func(static_cast(obj)); return true; - case generic_accountStateWalletV3::ID: - func(static_cast(obj)); + default: + return false; + } +} + +/** + * Calls specified function object with the specified object downcasted to the most-derived type. + * \param[in] obj Object to pass as an argument to the function object. + * \param[in] func Function object to which the object will be passed. + * \returns whether function object call has happened. Should always return true for correct parameters. + */ +template +bool downcast_call(dns_EntryData &obj, const T &func) { + switch (obj.get_id()) { + case dns_entryDataUnknown::ID: + func(static_cast(obj)); return true; - case generic_accountStateTestGiver::ID: - func(static_cast(obj)); + case dns_entryDataText::ID: + func(static_cast(obj)); return true; - case generic_accountStateUninited::ID: - func(static_cast(obj)); + case dns_entryDataNextResolver::ID: + func(static_cast(obj)); + return true; + case dns_entryDataSmcAddress::ID: + func(static_cast(obj)); + return true; + case dns_entryDataAdnlAddress::ID: + func(static_cast(obj)); + return true; + default: + return false; + } +} + +/** + * Calls specified function object with the specified object downcasted to the most-derived type. + * \param[in] obj Object to pass as an argument to the function object. + * \param[in] func Function object to which the object will be passed. + * \returns whether function object call has happened. Should always return true for correct parameters. + */ +template +bool downcast_call(msg_Data &obj, const T &func) { + switch (obj.get_id()) { + case msg_dataRaw::ID: + func(static_cast(obj)); + return true; + case msg_dataText::ID: + func(static_cast(obj)); + return true; + case msg_dataDecryptedText::ID: + func(static_cast(obj)); + return true; + case msg_dataEncryptedText::ID: + func(static_cast(obj)); return true; default: return false; @@ -581,6 +801,12 @@ bool downcast_call(tvm_StackEntry &obj, const T &func) { case tvm_stackEntryNumber::ID: func(static_cast(obj)); return true; + case tvm_stackEntryTuple::ID: + func(static_cast(obj)); + return true; + case tvm_stackEntryList::ID: + func(static_cast(obj)); + return true; case tvm_stackEntryUnsupported::ID: func(static_cast(obj)); return true; diff --git a/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api_json.cpp b/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api_json.cpp index bb29637762..335cbbc3d5 100644 --- a/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api_json.cpp +++ b/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api_json.cpp @@ -14,6 +14,53 @@ namespace ton { namespace tonlib_api{ using namespace td; +Result tl_constructor_from_string(tonlib_api::AccountState *object, const std::string &str) { + static const std::unordered_map m = { + {"raw.accountState", -531917254}, + {"testWallet.accountState", -2053909931}, + {"wallet.accountState", -390017192}, + {"wallet.v3.accountState", -1619351478}, + {"wallet.highload.v1.accountState", 1616372956}, + {"wallet.highload.v2.accountState", -1803723441}, + {"testGiver.accountState", -696813142}, + {"dns.accountState", 1727715434}, + {"uninited.accountState", 1522374408} + }; + auto it = m.find(str); + if (it == m.end()) { + return Status::Error(str + "Unknown class"); + } + return it->second; +} +Result tl_constructor_from_string(tonlib_api::Action *object, const std::string &str) { + static const std::unordered_map m = { + {"actionNoop", 1135848603}, + {"actionMsg", 246839120}, + {"actionDns", 1193750561} + }; + auto it = m.find(str); + if (it == m.end()) { + return Status::Error(str + "Unknown class"); + } + return it->second; +} +Result tl_constructor_from_string(tonlib_api::InitialAccountState *object, const std::string &str) { + static const std::unordered_map m = { + {"raw.initialAccountState", -337945529}, + {"testGiver.initialAccountState", -1448412176}, + {"testWallet.initialAccountState", 819380068}, + {"wallet.initialAccountState", -1122166790}, + {"wallet.v3.initialAccountState", -118074048}, + {"wallet.highload.v1.initialAccountState", -327901626}, + {"wallet.highload.v2.initialAccountState", 1966373161}, + {"dns.initialAccountState", 1842062527} + }; + auto it = m.find(str); + if (it == m.end()) { + return Status::Error(str + "Unknown class"); + } + return it->second; +} Result tl_constructor_from_string(tonlib_api::InputKey *object, const std::string &str) { static const std::unordered_map m = { {"inputKeyRegular", -555399522}, @@ -70,14 +117,38 @@ Result tl_constructor_from_string(tonlib_api::Update *object, const std:: } return it->second; } -Result tl_constructor_from_string(tonlib_api::generic_AccountState *object, const std::string &str) { +Result tl_constructor_from_string(tonlib_api::dns_Action *object, const std::string &str) { static const std::unordered_map m = { - {"generic.accountStateRaw", -1387096685}, - {"generic.accountStateTestWallet", -1041955397}, - {"generic.accountStateWallet", 942582925}, - {"generic.accountStateWalletV3", -281349583}, - {"generic.accountStateTestGiver", 1134654598}, - {"generic.accountStateUninited", -908702008} + {"dns.actionDeleteAll", 1067356318}, + {"dns.actionDelete", 775206882}, + {"dns.actionSet", -1374965309} + }; + auto it = m.find(str); + if (it == m.end()) { + return Status::Error(str + "Unknown class"); + } + return it->second; +} +Result tl_constructor_from_string(tonlib_api::dns_EntryData *object, const std::string &str) { + static const std::unordered_map m = { + {"dns.entryDataUnknown", -1285893248}, + {"dns.entryDataText", -792485614}, + {"dns.entryDataNextResolver", 330382792}, + {"dns.entryDataSmcAddress", -1759937982}, + {"dns.entryDataAdnlAddress", -1114064368} + }; + auto it = m.find(str); + if (it == m.end()) { + return Status::Error(str + "Unknown class"); + } + return it->second; +} +Result tl_constructor_from_string(tonlib_api::msg_Data *object, const std::string &str) { + static const std::unordered_map m = { + {"msg.dataRaw", 38878511}, + {"msg.dataText", -341560688}, + {"msg.dataDecryptedText", -1289133895}, + {"msg.dataEncryptedText", -296612902} }; auto it = m.find(str); if (it == m.end()) { @@ -101,6 +172,8 @@ Result tl_constructor_from_string(tonlib_api::tvm_StackEntry *object, con {"tvm.stackEntrySlice", 1395485477}, {"tvm.stackEntryCell", 1303473952}, {"tvm.stackEntryNumber", 1358642622}, + {"tvm.stackEntryTuple", -157391908}, + {"tvm.stackEntryList", -1186714229}, {"tvm.stackEntryUnsupported", 378880498} }; auto it = m.find(str); @@ -112,6 +185,20 @@ Result tl_constructor_from_string(tonlib_api::tvm_StackEntry *object, con Result tl_constructor_from_string(tonlib_api::Object *object, const std::string &str) { static const std::unordered_map m = { {"accountAddress", 755613099}, + {"accountRevisionList", 120583012}, + {"raw.accountState", -531917254}, + {"testWallet.accountState", -2053909931}, + {"wallet.accountState", -390017192}, + {"wallet.v3.accountState", -1619351478}, + {"wallet.highload.v1.accountState", 1616372956}, + {"wallet.highload.v2.accountState", -1803723441}, + {"testGiver.accountState", -696813142}, + {"dns.accountState", 1727715434}, + {"uninited.accountState", 1522374408}, + {"actionNoop", 1135848603}, + {"actionMsg", 246839120}, + {"actionDns", 1193750561}, + {"adnlAddress", 70358284}, {"bip39Hints", 1012243456}, {"config", -1538391496}, {"data", -414733967}, @@ -119,7 +206,17 @@ Result tl_constructor_from_string(tonlib_api::Object *object, const std:: {"exportedEncryptedKey", 2024406612}, {"exportedKey", -1449248297}, {"exportedPemKey", 1425473725}, + {"exportedUnencryptedKey", 730045160}, {"fees", 1676273340}, + {"fullAccountState", -686286006}, + {"raw.initialAccountState", -337945529}, + {"testGiver.initialAccountState", -1448412176}, + {"testWallet.initialAccountState", 819380068}, + {"wallet.initialAccountState", -1122166790}, + {"wallet.v3.initialAccountState", -118074048}, + {"wallet.highload.v1.initialAccountState", -327901626}, + {"wallet.highload.v2.initialAccountState", 1966373161}, + {"dns.initialAccountState", 1842062527}, {"inputKeyRegular", -555399522}, {"inputKeyFake", -1074054722}, {"key", -1978362923}, @@ -132,47 +229,54 @@ Result tl_constructor_from_string(tonlib_api::Object *object, const std:: {"logVerbosityLevel", 1734624234}, {"ok", -722616727}, {"options", -1924388359}, - {"sendGramsResult", 426872238}, {"syncStateDone", 1408448777}, {"syncStateInProgress", 107726023}, {"unpackedAccountAddress", 1892946998}, {"updateSendLiteServerQuery", -1555130916}, {"updateSyncState", 1204298718}, - {"generic.accountStateRaw", -1387096685}, - {"generic.accountStateTestWallet", -1041955397}, - {"generic.accountStateWallet", 942582925}, - {"generic.accountStateWalletV3", -281349583}, - {"generic.accountStateTestGiver", 1134654598}, - {"generic.accountStateUninited", -908702008}, + {"dns.actionDeleteAll", 1067356318}, + {"dns.actionDelete", 775206882}, + {"dns.actionSet", -1374965309}, + {"dns.entry", -1842435400}, + {"dns.entryDataUnknown", -1285893248}, + {"dns.entryDataText", -792485614}, + {"dns.entryDataNextResolver", 330382792}, + {"dns.entryDataSmcAddress", -1759937982}, + {"dns.entryDataAdnlAddress", -1114064368}, + {"dns.resolved", 2090272150}, + {"ton.blockId", -1185382494}, {"internal.transactionId", -989527262}, {"liteServer.info", -1250165133}, - {"options.configInfo", 165216422}, - {"query.fees", 725267759}, + {"msg.dataRaw", 38878511}, + {"msg.dataText", -341560688}, + {"msg.dataDecryptedText", -1289133895}, + {"msg.dataEncryptedText", -296612902}, + {"msg.dataArray", 1248461374}, + {"msg.message", 1349943761}, + {"options.configInfo", 451217371}, + {"options.info", -64676736}, + {"query.fees", 1614616510}, {"query.info", 1588635915}, - {"raw.accountState", 1205935434}, - {"raw.initialAccountState", 777456197}, - {"raw.message", -906281442}, + {"raw.fullAccountState", -1465398385}, + {"raw.message", -32842388}, {"raw.transaction", 1887601793}, {"raw.transactions", -2063931155}, {"smc.info", 1134270012}, {"smc.methodIdNumber", -1541162500}, {"smc.methodIdName", -249036908}, {"smc.runResult", 1413805043}, - {"testGiver.accountState", 860930426}, - {"testWallet.accountState", 305698744}, - {"testWallet.initialAccountState", -1231516227}, - {"tvm.cell", -859530316}, + {"ton.blockIdExt", 2031156378}, + {"tvm.cell", -413424735}, + {"tvm.list", 1270320392}, {"tvm.numberDecimal", 1172477619}, - {"tvm.slice", -1069968387}, + {"tvm.slice", 537299687}, {"tvm.stackEntrySlice", 1395485477}, {"tvm.stackEntryCell", 1303473952}, {"tvm.stackEntryNumber", 1358642622}, + {"tvm.stackEntryTuple", -157391908}, + {"tvm.stackEntryList", -1186714229}, {"tvm.stackEntryUnsupported", 378880498}, - {"uninited.accountState", -918880075}, - {"wallet.accountState", -1919815977}, - {"wallet.initialAccountState", -1079249978}, - {"wallet.v3.accountState", 1977698154}, - {"wallet.v3.initialAccountState", 283460879} + {"tvm.tuple", -1363953053} }; auto it = m.find(str); if (it == m.end()) { @@ -186,30 +290,35 @@ Result tl_constructor_from_string(tonlib_api::Function *object, const std {"changeLocalPassword", -401590337}, {"close", -1187782273}, {"createNewKey", -1861385712}, + {"createQuery", -1316835098}, {"decrypt", 357991854}, {"deleteAllKeys", 1608776483}, {"deleteKey", -1579595571}, + {"dns.resolve", -149238065}, {"encrypt", -1821422820}, {"exportEncryptedKey", 218237311}, {"exportKey", -1622353549}, {"exportPemKey", -643259462}, - {"generic.createSendGramsQuery", 208206338}, - {"generic.getAccountState", -657000446}, - {"generic.sendGrams", -553513162}, + {"exportUnencryptedKey", -634665152}, + {"getAccountAddress", -1159101819}, + {"getAccountState", -2116357050}, {"getBip39Hints", -1889640982}, {"getLogStream", 1167608667}, {"getLogTagVerbosityLevel", 951004547}, {"getLogTags", -254449190}, {"getLogVerbosityLevel", 594057956}, + {"guessAccountRevision", 1463344293}, {"importEncryptedKey", 656724958}, {"importKey", -1607900903}, {"importPemKey", 76385617}, - {"init", -2014661877}, + {"importUnencryptedKey", -1184671467}, + {"init", -1000594762}, {"kdf", -1667861635}, {"liteServer.getInfo", 1435327470}, + {"msg.decrypt", 1131086633}, {"onLiteServerQueryError", -677427533}, {"onLiteServerQueryResult", 2056444510}, - {"options.setConfig", 646497241}, + {"options.setConfig", 1870064579}, {"options.validateConfig", -346965447}, {"packAccountAddress", -1388561940}, {"query.estimateFees", -957002175}, @@ -218,9 +327,8 @@ Result tl_constructor_from_string(tonlib_api::Function *object, const std {"query.send", 925242739}, {"raw.createAndSendMessage", -772224603}, {"raw.createQuery", -1928557909}, - {"raw.getAccountAddress", -521283849}, - {"raw.getAccountState", 663706721}, - {"raw.getTransactions", 935377269}, + {"raw.getAccountState", -1327847118}, + {"raw.getTransactions", 1029612317}, {"raw.sendMessage", -1789427488}, {"runTests", -2039925427}, {"setLogStream", -1364199535}, @@ -231,20 +339,9 @@ Result tl_constructor_from_string(tonlib_api::Function *object, const std {"smc.getState", -214390293}, {"smc.load", -903491521}, {"smc.runGetMethod", -255261270}, - {"sync", -1617065525}, - {"testGiver.getAccountAddress", -540100768}, - {"testGiver.getAccountState", 267738275}, - {"testGiver.sendGrams", -1785750375}, - {"testWallet.getAccountAddress", -1557748223}, - {"testWallet.getAccountState", 654082364}, - {"testWallet.init", -1417409140}, - {"testWallet.sendGrams", 573748322}, + {"sync", -1875977070}, {"unpackAccountAddress", -682459063}, - {"wallet.getAccountAddress", -1004103180}, - {"wallet.getAccountState", 462294850}, - {"wallet.init", -395706309}, - {"wallet.sendGrams", 297317621}, - {"wallet.v3.getAccountAddress", 1011655671} + {"withBlock", -789093723} }; auto it = m.find(str); if (it == m.end()) { @@ -261,6 +358,156 @@ Status from_json(tonlib_api::accountAddress &to, JsonObject &from) { } return Status::OK(); } +Status from_json(tonlib_api::accountRevisionList &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "revisions", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.revisions_, value)); + } + } + return Status::OK(); +} +Status from_json(tonlib_api::raw_accountState &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "code", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json_bytes(to.code_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "data", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json_bytes(to.data_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "frozen_hash", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json_bytes(to.frozen_hash_, value)); + } + } + return Status::OK(); +} +Status from_json(tonlib_api::testWallet_accountState &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "seqno", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.seqno_, value)); + } + } + return Status::OK(); +} +Status from_json(tonlib_api::wallet_accountState &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "seqno", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.seqno_, value)); + } + } + return Status::OK(); +} +Status from_json(tonlib_api::wallet_v3_accountState &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "wallet_id", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.wallet_id_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "seqno", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.seqno_, value)); + } + } + return Status::OK(); +} +Status from_json(tonlib_api::wallet_highload_v1_accountState &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "wallet_id", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.wallet_id_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "seqno", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.seqno_, value)); + } + } + return Status::OK(); +} +Status from_json(tonlib_api::wallet_highload_v2_accountState &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "wallet_id", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.wallet_id_, value)); + } + } + return Status::OK(); +} +Status from_json(tonlib_api::testGiver_accountState &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "seqno", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.seqno_, value)); + } + } + return Status::OK(); +} +Status from_json(tonlib_api::dns_accountState &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "wallet_id", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.wallet_id_, value)); + } + } + return Status::OK(); +} +Status from_json(tonlib_api::uninited_accountState &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "frozen_hash", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json_bytes(to.frozen_hash_, value)); + } + } + return Status::OK(); +} +Status from_json(tonlib_api::actionNoop &to, JsonObject &from) { + return Status::OK(); +} +Status from_json(tonlib_api::actionMsg &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "messages", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.messages_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "allow_send_to_uninited", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.allow_send_to_uninited_, value)); + } + } + return Status::OK(); +} +Status from_json(tonlib_api::actionDns &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "actions", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.actions_, value)); + } + } + return Status::OK(); +} +Status from_json(tonlib_api::adnlAddress &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "adnl_address", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.adnl_address_, value)); + } + } + return Status::OK(); +} Status from_json(tonlib_api::bip39Hints &to, JsonObject &from) { { TRY_RESULT(value, get_json_object_field(from, "words", JsonValue::Type::Null, true)); @@ -348,6 +595,15 @@ Status from_json(tonlib_api::exportedPemKey &to, JsonObject &from) { } return Status::OK(); } +Status from_json(tonlib_api::exportedUnencryptedKey &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "data", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json_bytes(to.data_, value)); + } + } + return Status::OK(); +} Status from_json(tonlib_api::fees &to, JsonObject &from) { { TRY_RESULT(value, get_json_object_field(from, "in_fwd_fee", JsonValue::Type::Null, true)); @@ -375,6 +631,135 @@ Status from_json(tonlib_api::fees &to, JsonObject &from) { } return Status::OK(); } +Status from_json(tonlib_api::fullAccountState &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "balance", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.balance_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "last_transaction_id", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.last_transaction_id_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "block_id", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.block_id_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "sync_utime", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.sync_utime_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "account_state", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.account_state_, value)); + } + } + return Status::OK(); +} +Status from_json(tonlib_api::raw_initialAccountState &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "code", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json_bytes(to.code_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "data", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json_bytes(to.data_, value)); + } + } + return Status::OK(); +} +Status from_json(tonlib_api::testGiver_initialAccountState &to, JsonObject &from) { + return Status::OK(); +} +Status from_json(tonlib_api::testWallet_initialAccountState &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "public_key", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.public_key_, value)); + } + } + return Status::OK(); +} +Status from_json(tonlib_api::wallet_initialAccountState &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "public_key", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.public_key_, value)); + } + } + return Status::OK(); +} +Status from_json(tonlib_api::wallet_v3_initialAccountState &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "public_key", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.public_key_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "wallet_id", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.wallet_id_, value)); + } + } + return Status::OK(); +} +Status from_json(tonlib_api::wallet_highload_v1_initialAccountState &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "public_key", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.public_key_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "wallet_id", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.wallet_id_, value)); + } + } + return Status::OK(); +} +Status from_json(tonlib_api::wallet_highload_v2_initialAccountState &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "public_key", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.public_key_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "wallet_id", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.wallet_id_, value)); + } + } + return Status::OK(); +} +Status from_json(tonlib_api::dns_initialAccountState &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "public_key", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.public_key_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "wallet_id", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.wallet_id_, value)); + } + } + return Status::OK(); +} Status from_json(tonlib_api::inputKeyRegular &to, JsonObject &from) { { TRY_RESULT(value, get_json_object_field(from, "key", JsonValue::Type::Null, true)); @@ -477,21 +862,6 @@ Status from_json(tonlib_api::options &to, JsonObject &from) { } return Status::OK(); } -Status from_json(tonlib_api::sendGramsResult &to, JsonObject &from) { - { - TRY_RESULT(value, get_json_object_field(from, "sent_until", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.sent_until_, value)); - } - } - { - TRY_RESULT(value, get_json_object_field(from, "body_hash", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json_bytes(to.body_hash_, value)); - } - } - return Status::OK(); -} Status from_json(tonlib_api::syncStateDone &to, JsonObject &from) { return Status::OK(); } @@ -567,56 +937,125 @@ Status from_json(tonlib_api::updateSyncState &to, JsonObject &from) { } return Status::OK(); } -Status from_json(tonlib_api::generic_accountStateRaw &to, JsonObject &from) { +Status from_json(tonlib_api::dns_actionDeleteAll &to, JsonObject &from) { + return Status::OK(); +} +Status from_json(tonlib_api::dns_actionDelete &to, JsonObject &from) { { - TRY_RESULT(value, get_json_object_field(from, "account_state", JsonValue::Type::Null, true)); + TRY_RESULT(value, get_json_object_field(from, "name", JsonValue::Type::Null, true)); if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.account_state_, value)); + TRY_STATUS(from_json(to.name_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "category", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.category_, value)); } } return Status::OK(); } -Status from_json(tonlib_api::generic_accountStateTestWallet &to, JsonObject &from) { +Status from_json(tonlib_api::dns_actionSet &to, JsonObject &from) { { - TRY_RESULT(value, get_json_object_field(from, "account_state", JsonValue::Type::Null, true)); + TRY_RESULT(value, get_json_object_field(from, "entry", JsonValue::Type::Null, true)); if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.account_state_, value)); + TRY_STATUS(from_json(to.entry_, value)); } } return Status::OK(); } -Status from_json(tonlib_api::generic_accountStateWallet &to, JsonObject &from) { +Status from_json(tonlib_api::dns_entry &to, JsonObject &from) { { - TRY_RESULT(value, get_json_object_field(from, "account_state", JsonValue::Type::Null, true)); + TRY_RESULT(value, get_json_object_field(from, "name", JsonValue::Type::Null, true)); if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.account_state_, value)); + TRY_STATUS(from_json(to.name_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "category", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.category_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "entry", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.entry_, value)); } } return Status::OK(); } -Status from_json(tonlib_api::generic_accountStateWalletV3 &to, JsonObject &from) { +Status from_json(tonlib_api::dns_entryDataUnknown &to, JsonObject &from) { { - TRY_RESULT(value, get_json_object_field(from, "account_state", JsonValue::Type::Null, true)); + TRY_RESULT(value, get_json_object_field(from, "bytes", JsonValue::Type::Null, true)); if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.account_state_, value)); + TRY_STATUS(from_json_bytes(to.bytes_, value)); } } return Status::OK(); } -Status from_json(tonlib_api::generic_accountStateTestGiver &to, JsonObject &from) { +Status from_json(tonlib_api::dns_entryDataText &to, JsonObject &from) { { - TRY_RESULT(value, get_json_object_field(from, "account_state", JsonValue::Type::Null, true)); + TRY_RESULT(value, get_json_object_field(from, "text", JsonValue::Type::Null, true)); if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.account_state_, value)); + TRY_STATUS(from_json(to.text_, value)); } } return Status::OK(); } -Status from_json(tonlib_api::generic_accountStateUninited &to, JsonObject &from) { +Status from_json(tonlib_api::dns_entryDataNextResolver &to, JsonObject &from) { { - TRY_RESULT(value, get_json_object_field(from, "account_state", JsonValue::Type::Null, true)); + TRY_RESULT(value, get_json_object_field(from, "resolver", JsonValue::Type::Null, true)); if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.account_state_, value)); + TRY_STATUS(from_json(to.resolver_, value)); + } + } + return Status::OK(); +} +Status from_json(tonlib_api::dns_entryDataSmcAddress &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "smc_address", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.smc_address_, value)); + } + } + return Status::OK(); +} +Status from_json(tonlib_api::dns_entryDataAdnlAddress &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "adnl_address", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.adnl_address_, value)); + } + } + return Status::OK(); +} +Status from_json(tonlib_api::dns_resolved &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "entries", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.entries_, value)); + } + } + return Status::OK(); +} +Status from_json(tonlib_api::ton_blockId &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "workchain", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.workchain_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "shard", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.shard_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "seqno", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.seqno_, value)); } } return Status::OK(); @@ -657,6 +1096,72 @@ Status from_json(tonlib_api::liteServer_info &to, JsonObject &from) { } return Status::OK(); } +Status from_json(tonlib_api::msg_dataRaw &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "body", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json_bytes(to.body_, value)); + } + } + return Status::OK(); +} +Status from_json(tonlib_api::msg_dataText &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "text", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json_bytes(to.text_, value)); + } + } + return Status::OK(); +} +Status from_json(tonlib_api::msg_dataDecryptedText &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "text", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json_bytes(to.text_, value)); + } + } + return Status::OK(); +} +Status from_json(tonlib_api::msg_dataEncryptedText &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "text", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json_bytes(to.text_, value)); + } + } + return Status::OK(); +} +Status from_json(tonlib_api::msg_dataArray &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "elements", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.elements_, value)); + } + } + return Status::OK(); +} +Status from_json(tonlib_api::msg_message &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "destination", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.destination_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "amount", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.amount_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "data", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.data_, value)); + } + } + return Status::OK(); +} Status from_json(tonlib_api::options_configInfo &to, JsonObject &from) { { TRY_RESULT(value, get_json_object_field(from, "default_wallet_id", JsonValue::Type::Null, true)); @@ -666,6 +1171,15 @@ Status from_json(tonlib_api::options_configInfo &to, JsonObject &from) { } return Status::OK(); } +Status from_json(tonlib_api::options_info &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "config_info", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.config_info_, value)); + } + } + return Status::OK(); +} Status from_json(tonlib_api::query_fees &to, JsonObject &from) { { TRY_RESULT(value, get_json_object_field(from, "source_fees", JsonValue::Type::Null, true)); @@ -702,7 +1216,7 @@ Status from_json(tonlib_api::query_info &to, JsonObject &from) { } return Status::OK(); } -Status from_json(tonlib_api::raw_accountState &to, JsonObject &from) { +Status from_json(tonlib_api::raw_fullAccountState &to, JsonObject &from) { { TRY_RESULT(value, get_json_object_field(from, "balance", JsonValue::Type::Null, true)); if (value.type() != JsonValue::Type::Null) { @@ -727,6 +1241,12 @@ Status from_json(tonlib_api::raw_accountState &to, JsonObject &from) { TRY_STATUS(from_json(to.last_transaction_id_, value)); } } + { + TRY_RESULT(value, get_json_object_field(from, "block_id", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.block_id_, value)); + } + } { TRY_RESULT(value, get_json_object_field(from, "frozen_hash", JsonValue::Type::Null, true)); if (value.type() != JsonValue::Type::Null) { @@ -741,21 +1261,6 @@ Status from_json(tonlib_api::raw_accountState &to, JsonObject &from) { } return Status::OK(); } -Status from_json(tonlib_api::raw_initialAccountState &to, JsonObject &from) { - { - TRY_RESULT(value, get_json_object_field(from, "code", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json_bytes(to.code_, value)); - } - } - { - TRY_RESULT(value, get_json_object_field(from, "data", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json_bytes(to.data_, value)); - } - } - return Status::OK(); -} Status from_json(tonlib_api::raw_message &to, JsonObject &from) { { TRY_RESULT(value, get_json_object_field(from, "source", JsonValue::Type::Null, true)); @@ -800,9 +1305,9 @@ Status from_json(tonlib_api::raw_message &to, JsonObject &from) { } } { - TRY_RESULT(value, get_json_object_field(from, "message", JsonValue::Type::Null, true)); + TRY_RESULT(value, get_json_object_field(from, "msg_data", JsonValue::Type::Null, true)); if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json_bytes(to.message_, value)); + TRY_STATUS(from_json(to.msg_data_, value)); } } return Status::OK(); @@ -921,11 +1426,17 @@ Status from_json(tonlib_api::smc_runResult &to, JsonObject &from) { } return Status::OK(); } -Status from_json(tonlib_api::testGiver_accountState &to, JsonObject &from) { +Status from_json(tonlib_api::ton_blockIdExt &to, JsonObject &from) { { - TRY_RESULT(value, get_json_object_field(from, "balance", JsonValue::Type::Null, true)); + TRY_RESULT(value, get_json_object_field(from, "workchain", JsonValue::Type::Null, true)); if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.balance_, value)); + TRY_STATUS(from_json(to.workchain_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "shard", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.shard_, value)); } } { @@ -935,51 +1446,15 @@ Status from_json(tonlib_api::testGiver_accountState &to, JsonObject &from) { } } { - TRY_RESULT(value, get_json_object_field(from, "last_transaction_id", JsonValue::Type::Null, true)); + TRY_RESULT(value, get_json_object_field(from, "root_hash", JsonValue::Type::Null, true)); if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.last_transaction_id_, value)); + TRY_STATUS(from_json_bytes(to.root_hash_, value)); } } { - TRY_RESULT(value, get_json_object_field(from, "sync_utime", JsonValue::Type::Null, true)); + TRY_RESULT(value, get_json_object_field(from, "file_hash", JsonValue::Type::Null, true)); if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.sync_utime_, value)); - } - } - return Status::OK(); -} -Status from_json(tonlib_api::testWallet_accountState &to, JsonObject &from) { - { - TRY_RESULT(value, get_json_object_field(from, "balance", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.balance_, value)); - } - } - { - TRY_RESULT(value, get_json_object_field(from, "seqno", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.seqno_, value)); - } - } - { - TRY_RESULT(value, get_json_object_field(from, "last_transaction_id", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.last_transaction_id_, value)); - } - } - { - TRY_RESULT(value, get_json_object_field(from, "sync_utime", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.sync_utime_, value)); - } - } - return Status::OK(); -} -Status from_json(tonlib_api::testWallet_initialAccountState &to, JsonObject &from) { - { - TRY_RESULT(value, get_json_object_field(from, "public_key", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.public_key_, value)); + TRY_STATUS(from_json_bytes(to.file_hash_, value)); } } return Status::OK(); @@ -988,7 +1463,16 @@ Status from_json(tonlib_api::tvm_cell &to, JsonObject &from) { { TRY_RESULT(value, get_json_object_field(from, "bytes", JsonValue::Type::Null, true)); if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.bytes_, value)); + TRY_STATUS(from_json_bytes(to.bytes_, value)); + } + } + return Status::OK(); +} +Status from_json(tonlib_api::tvm_list &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "elements", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.elements_, value)); } } return Status::OK(); @@ -1006,7 +1490,7 @@ Status from_json(tonlib_api::tvm_slice &to, JsonObject &from) { { TRY_RESULT(value, get_json_object_field(from, "bytes", JsonValue::Type::Null, true)); if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.bytes_, value)); + TRY_STATUS(from_json_bytes(to.bytes_, value)); } } return Status::OK(); @@ -1038,116 +1522,32 @@ Status from_json(tonlib_api::tvm_stackEntryNumber &to, JsonObject &from) { } return Status::OK(); } +Status from_json(tonlib_api::tvm_stackEntryTuple &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "tuple", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.tuple_, value)); + } + } + return Status::OK(); +} +Status from_json(tonlib_api::tvm_stackEntryList &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "list", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.list_, value)); + } + } + return Status::OK(); +} Status from_json(tonlib_api::tvm_stackEntryUnsupported &to, JsonObject &from) { return Status::OK(); } -Status from_json(tonlib_api::uninited_accountState &to, JsonObject &from) { +Status from_json(tonlib_api::tvm_tuple &to, JsonObject &from) { { - TRY_RESULT(value, get_json_object_field(from, "balance", JsonValue::Type::Null, true)); + TRY_RESULT(value, get_json_object_field(from, "elements", JsonValue::Type::Null, true)); if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.balance_, value)); - } - } - { - TRY_RESULT(value, get_json_object_field(from, "last_transaction_id", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.last_transaction_id_, value)); - } - } - { - TRY_RESULT(value, get_json_object_field(from, "frozen_hash", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json_bytes(to.frozen_hash_, value)); - } - } - { - TRY_RESULT(value, get_json_object_field(from, "sync_utime", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.sync_utime_, value)); - } - } - return Status::OK(); -} -Status from_json(tonlib_api::wallet_accountState &to, JsonObject &from) { - { - TRY_RESULT(value, get_json_object_field(from, "balance", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.balance_, value)); - } - } - { - TRY_RESULT(value, get_json_object_field(from, "seqno", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.seqno_, value)); - } - } - { - TRY_RESULT(value, get_json_object_field(from, "last_transaction_id", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.last_transaction_id_, value)); - } - } - { - TRY_RESULT(value, get_json_object_field(from, "sync_utime", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.sync_utime_, value)); - } - } - return Status::OK(); -} -Status from_json(tonlib_api::wallet_initialAccountState &to, JsonObject &from) { - { - TRY_RESULT(value, get_json_object_field(from, "public_key", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.public_key_, value)); - } - } - return Status::OK(); -} -Status from_json(tonlib_api::wallet_v3_accountState &to, JsonObject &from) { - { - TRY_RESULT(value, get_json_object_field(from, "balance", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.balance_, value)); - } - } - { - TRY_RESULT(value, get_json_object_field(from, "wallet_id", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.wallet_id_, value)); - } - } - { - TRY_RESULT(value, get_json_object_field(from, "seqno", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.seqno_, value)); - } - } - { - TRY_RESULT(value, get_json_object_field(from, "last_transaction_id", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.last_transaction_id_, value)); - } - } - { - TRY_RESULT(value, get_json_object_field(from, "sync_utime", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.sync_utime_, value)); - } - } - return Status::OK(); -} -Status from_json(tonlib_api::wallet_v3_initialAccountState &to, JsonObject &from) { - { - TRY_RESULT(value, get_json_object_field(from, "public_key", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.public_key_, value)); - } - } - { - TRY_RESULT(value, get_json_object_field(from, "wallet_id", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.wallet_id_, value)); + TRY_STATUS(from_json(to.elements_, value)); } } return Status::OK(); @@ -1206,6 +1606,33 @@ Status from_json(tonlib_api::createNewKey &to, JsonObject &from) { } return Status::OK(); } +Status from_json(tonlib_api::createQuery &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "private_key", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.private_key_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "address", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.address_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "timeout", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.timeout_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "action", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.action_, value)); + } + } + return Status::OK(); +} Status from_json(tonlib_api::decrypt &to, JsonObject &from) { { TRY_RESULT(value, get_json_object_field(from, "encrypted_data", JsonValue::Type::Null, true)); @@ -1233,6 +1660,33 @@ Status from_json(tonlib_api::deleteKey &to, JsonObject &from) { } return Status::OK(); } +Status from_json(tonlib_api::dns_resolve &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "account_address", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.account_address_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "name", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.name_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "category", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.category_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "ttl", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.ttl_, value)); + } + } + return Status::OK(); +} Status from_json(tonlib_api::encrypt &to, JsonObject &from) { { TRY_RESULT(value, get_json_object_field(from, "decrypted_data", JsonValue::Type::Null, true)); @@ -1287,52 +1741,31 @@ Status from_json(tonlib_api::exportPemKey &to, JsonObject &from) { } return Status::OK(); } -Status from_json(tonlib_api::generic_createSendGramsQuery &to, JsonObject &from) { +Status from_json(tonlib_api::exportUnencryptedKey &to, JsonObject &from) { { - TRY_RESULT(value, get_json_object_field(from, "private_key", JsonValue::Type::Null, true)); + TRY_RESULT(value, get_json_object_field(from, "input_key", JsonValue::Type::Null, true)); if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.private_key_, value)); - } - } - { - TRY_RESULT(value, get_json_object_field(from, "source", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.source_, value)); - } - } - { - TRY_RESULT(value, get_json_object_field(from, "destination", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.destination_, value)); - } - } - { - TRY_RESULT(value, get_json_object_field(from, "amount", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.amount_, value)); - } - } - { - TRY_RESULT(value, get_json_object_field(from, "timeout", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.timeout_, value)); - } - } - { - TRY_RESULT(value, get_json_object_field(from, "allow_send_to_uninited", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.allow_send_to_uninited_, value)); - } - } - { - TRY_RESULT(value, get_json_object_field(from, "message", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json_bytes(to.message_, value)); + TRY_STATUS(from_json(to.input_key_, value)); } } return Status::OK(); } -Status from_json(tonlib_api::generic_getAccountState &to, JsonObject &from) { +Status from_json(tonlib_api::getAccountAddress &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "initial_account_state", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.initial_account_state_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "revision", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.revision_, value)); + } + } + return Status::OK(); +} +Status from_json(tonlib_api::getAccountState &to, JsonObject &from) { { TRY_RESULT(value, get_json_object_field(from, "account_address", JsonValue::Type::Null, true)); if (value.type() != JsonValue::Type::Null) { @@ -1341,51 +1774,6 @@ Status from_json(tonlib_api::generic_getAccountState &to, JsonObject &from) { } return Status::OK(); } -Status from_json(tonlib_api::generic_sendGrams &to, JsonObject &from) { - { - TRY_RESULT(value, get_json_object_field(from, "private_key", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.private_key_, value)); - } - } - { - TRY_RESULT(value, get_json_object_field(from, "source", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.source_, value)); - } - } - { - TRY_RESULT(value, get_json_object_field(from, "destination", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.destination_, value)); - } - } - { - TRY_RESULT(value, get_json_object_field(from, "amount", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.amount_, value)); - } - } - { - TRY_RESULT(value, get_json_object_field(from, "timeout", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.timeout_, value)); - } - } - { - TRY_RESULT(value, get_json_object_field(from, "allow_send_to_uninited", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.allow_send_to_uninited_, value)); - } - } - { - TRY_RESULT(value, get_json_object_field(from, "message", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json_bytes(to.message_, value)); - } - } - return Status::OK(); -} Status from_json(tonlib_api::getBip39Hints &to, JsonObject &from) { { TRY_RESULT(value, get_json_object_field(from, "prefix", JsonValue::Type::Null, true)); @@ -1413,6 +1801,15 @@ Status from_json(tonlib_api::getLogTags &to, JsonObject &from) { Status from_json(tonlib_api::getLogVerbosityLevel &to, JsonObject &from) { return Status::OK(); } +Status from_json(tonlib_api::guessAccountRevision &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "initial_account_state", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.initial_account_state_, value)); + } + } + return Status::OK(); +} Status from_json(tonlib_api::importEncryptedKey &to, JsonObject &from) { { TRY_RESULT(value, get_json_object_field(from, "local_password", JsonValue::Type::Null, true)); @@ -1476,6 +1873,21 @@ Status from_json(tonlib_api::importPemKey &to, JsonObject &from) { } return Status::OK(); } +Status from_json(tonlib_api::importUnencryptedKey &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "local_password", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json_bytes(to.local_password_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "exported_unencrypted_key", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.exported_unencrypted_key_, value)); + } + } + return Status::OK(); +} Status from_json(tonlib_api::init &to, JsonObject &from) { { TRY_RESULT(value, get_json_object_field(from, "options", JsonValue::Type::Null, true)); @@ -1509,6 +1921,21 @@ Status from_json(tonlib_api::kdf &to, JsonObject &from) { Status from_json(tonlib_api::liteServer_getInfo &to, JsonObject &from) { return Status::OK(); } +Status from_json(tonlib_api::msg_decrypt &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "input_key", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.input_key_, value)); + } + } + { + TRY_RESULT(value, get_json_object_field(from, "data", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.data_, value)); + } + } + return Status::OK(); +} Status from_json(tonlib_api::onLiteServerQueryError &to, JsonObject &from) { { TRY_RESULT(value, get_json_object_field(from, "id", JsonValue::Type::Null, true)); @@ -1656,15 +2083,6 @@ Status from_json(tonlib_api::raw_createQuery &to, JsonObject &from) { } return Status::OK(); } -Status from_json(tonlib_api::raw_getAccountAddress &to, JsonObject &from) { - { - TRY_RESULT(value, get_json_object_field(from, "initital_account_state", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.initital_account_state_, value)); - } - } - return Status::OK(); -} Status from_json(tonlib_api::raw_getAccountState &to, JsonObject &from) { { TRY_RESULT(value, get_json_object_field(from, "account_address", JsonValue::Type::Null, true)); @@ -1675,6 +2093,12 @@ Status from_json(tonlib_api::raw_getAccountState &to, JsonObject &from) { return Status::OK(); } Status from_json(tonlib_api::raw_getTransactions &to, JsonObject &from) { + { + TRY_RESULT(value, get_json_object_field(from, "private_key", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json(to.private_key_, value)); + } + } { TRY_RESULT(value, get_json_object_field(from, "account_address", JsonValue::Type::Null, true)); if (value.type() != JsonValue::Type::Null) { @@ -1800,99 +2224,6 @@ Status from_json(tonlib_api::smc_runGetMethod &to, JsonObject &from) { Status from_json(tonlib_api::sync &to, JsonObject &from) { return Status::OK(); } -Status from_json(tonlib_api::testGiver_getAccountAddress &to, JsonObject &from) { - return Status::OK(); -} -Status from_json(tonlib_api::testGiver_getAccountState &to, JsonObject &from) { - return Status::OK(); -} -Status from_json(tonlib_api::testGiver_sendGrams &to, JsonObject &from) { - { - TRY_RESULT(value, get_json_object_field(from, "destination", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.destination_, value)); - } - } - { - TRY_RESULT(value, get_json_object_field(from, "seqno", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.seqno_, value)); - } - } - { - TRY_RESULT(value, get_json_object_field(from, "amount", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.amount_, value)); - } - } - { - TRY_RESULT(value, get_json_object_field(from, "message", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json_bytes(to.message_, value)); - } - } - return Status::OK(); -} -Status from_json(tonlib_api::testWallet_getAccountAddress &to, JsonObject &from) { - { - TRY_RESULT(value, get_json_object_field(from, "initital_account_state", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.initital_account_state_, value)); - } - } - return Status::OK(); -} -Status from_json(tonlib_api::testWallet_getAccountState &to, JsonObject &from) { - { - TRY_RESULT(value, get_json_object_field(from, "account_address", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.account_address_, value)); - } - } - return Status::OK(); -} -Status from_json(tonlib_api::testWallet_init &to, JsonObject &from) { - { - TRY_RESULT(value, get_json_object_field(from, "private_key", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.private_key_, value)); - } - } - return Status::OK(); -} -Status from_json(tonlib_api::testWallet_sendGrams &to, JsonObject &from) { - { - TRY_RESULT(value, get_json_object_field(from, "private_key", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.private_key_, value)); - } - } - { - TRY_RESULT(value, get_json_object_field(from, "destination", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.destination_, value)); - } - } - { - TRY_RESULT(value, get_json_object_field(from, "seqno", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.seqno_, value)); - } - } - { - TRY_RESULT(value, get_json_object_field(from, "amount", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.amount_, value)); - } - } - { - TRY_RESULT(value, get_json_object_field(from, "message", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json_bytes(to.message_, value)); - } - } - return Status::OK(); -} Status from_json(tonlib_api::unpackAccountAddress &to, JsonObject &from) { { TRY_RESULT(value, get_json_object_field(from, "account_address", JsonValue::Type::Null, true)); @@ -1902,77 +2233,17 @@ Status from_json(tonlib_api::unpackAccountAddress &to, JsonObject &from) { } return Status::OK(); } -Status from_json(tonlib_api::wallet_getAccountAddress &to, JsonObject &from) { +Status from_json(tonlib_api::withBlock &to, JsonObject &from) { { - TRY_RESULT(value, get_json_object_field(from, "initital_account_state", JsonValue::Type::Null, true)); + TRY_RESULT(value, get_json_object_field(from, "id", JsonValue::Type::Null, true)); if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.initital_account_state_, value)); - } - } - return Status::OK(); -} -Status from_json(tonlib_api::wallet_getAccountState &to, JsonObject &from) { - { - TRY_RESULT(value, get_json_object_field(from, "account_address", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.account_address_, value)); - } - } - return Status::OK(); -} -Status from_json(tonlib_api::wallet_init &to, JsonObject &from) { - { - TRY_RESULT(value, get_json_object_field(from, "private_key", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.private_key_, value)); - } - } - return Status::OK(); -} -Status from_json(tonlib_api::wallet_sendGrams &to, JsonObject &from) { - { - TRY_RESULT(value, get_json_object_field(from, "private_key", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.private_key_, value)); + TRY_STATUS(from_json(to.id_, value)); } } { - TRY_RESULT(value, get_json_object_field(from, "destination", JsonValue::Type::Null, true)); + TRY_RESULT(value, get_json_object_field(from, "function", JsonValue::Type::Null, true)); if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.destination_, value)); - } - } - { - TRY_RESULT(value, get_json_object_field(from, "seqno", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.seqno_, value)); - } - } - { - TRY_RESULT(value, get_json_object_field(from, "valid_until", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.valid_until_, value)); - } - } - { - TRY_RESULT(value, get_json_object_field(from, "amount", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.amount_, value)); - } - } - { - TRY_RESULT(value, get_json_object_field(from, "message", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json_bytes(to.message_, value)); - } - } - return Status::OK(); -} -Status from_json(tonlib_api::wallet_v3_getAccountAddress &to, JsonObject &from) { - { - TRY_RESULT(value, get_json_object_field(from, "initital_account_state", JsonValue::Type::Null, true)); - if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.initital_account_state_, value)); + TRY_STATUS(from_json(to.function_, value)); } } return Status::OK(); @@ -1982,6 +2253,86 @@ void to_json(JsonValueScope &jv, const tonlib_api::accountAddress &object) { jo << ctie("@type", "accountAddress"); jo << ctie("account_address", ToJson(object.account_address_)); } +void to_json(JsonValueScope &jv, const tonlib_api::accountRevisionList &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "accountRevisionList"); + jo << ctie("revisions", ToJson(object.revisions_)); +} +void to_json(JsonValueScope &jv, const tonlib_api::AccountState &object) { + tonlib_api::downcast_call(const_cast(object), [&jv](const auto &object) { to_json(jv, object); }); +} +void to_json(JsonValueScope &jv, const tonlib_api::raw_accountState &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "raw.accountState"); + jo << ctie("code", ToJson(JsonBytes{object.code_})); + jo << ctie("data", ToJson(JsonBytes{object.data_})); + jo << ctie("frozen_hash", ToJson(JsonBytes{object.frozen_hash_})); +} +void to_json(JsonValueScope &jv, const tonlib_api::testWallet_accountState &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "testWallet.accountState"); + jo << ctie("seqno", ToJson(object.seqno_)); +} +void to_json(JsonValueScope &jv, const tonlib_api::wallet_accountState &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "wallet.accountState"); + jo << ctie("seqno", ToJson(object.seqno_)); +} +void to_json(JsonValueScope &jv, const tonlib_api::wallet_v3_accountState &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "wallet.v3.accountState"); + jo << ctie("wallet_id", ToJson(JsonInt64{object.wallet_id_})); + jo << ctie("seqno", ToJson(object.seqno_)); +} +void to_json(JsonValueScope &jv, const tonlib_api::wallet_highload_v1_accountState &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "wallet.highload.v1.accountState"); + jo << ctie("wallet_id", ToJson(JsonInt64{object.wallet_id_})); + jo << ctie("seqno", ToJson(object.seqno_)); +} +void to_json(JsonValueScope &jv, const tonlib_api::wallet_highload_v2_accountState &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "wallet.highload.v2.accountState"); + jo << ctie("wallet_id", ToJson(JsonInt64{object.wallet_id_})); +} +void to_json(JsonValueScope &jv, const tonlib_api::testGiver_accountState &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "testGiver.accountState"); + jo << ctie("seqno", ToJson(object.seqno_)); +} +void to_json(JsonValueScope &jv, const tonlib_api::dns_accountState &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "dns.accountState"); + jo << ctie("wallet_id", ToJson(JsonInt64{object.wallet_id_})); +} +void to_json(JsonValueScope &jv, const tonlib_api::uninited_accountState &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "uninited.accountState"); + jo << ctie("frozen_hash", ToJson(JsonBytes{object.frozen_hash_})); +} +void to_json(JsonValueScope &jv, const tonlib_api::Action &object) { + tonlib_api::downcast_call(const_cast(object), [&jv](const auto &object) { to_json(jv, object); }); +} +void to_json(JsonValueScope &jv, const tonlib_api::actionNoop &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "actionNoop"); +} +void to_json(JsonValueScope &jv, const tonlib_api::actionMsg &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "actionMsg"); + jo << ctie("messages", ToJson(object.messages_)); + jo << ctie("allow_send_to_uninited", ToJson(object.allow_send_to_uninited_)); +} +void to_json(JsonValueScope &jv, const tonlib_api::actionDns &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "actionDns"); + jo << ctie("actions", ToJson(object.actions_)); +} +void to_json(JsonValueScope &jv, const tonlib_api::adnlAddress &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "adnlAddress"); + jo << ctie("adnl_address", ToJson(object.adnl_address_)); +} void to_json(JsonValueScope &jv, const tonlib_api::bip39Hints &object) { auto jo = jv.enter_object(); jo << ctie("@type", "bip39Hints"); @@ -2021,6 +2372,11 @@ void to_json(JsonValueScope &jv, const tonlib_api::exportedPemKey &object) { jo << ctie("@type", "exportedPemKey"); jo << ctie("pem", ToJson(object.pem_)); } +void to_json(JsonValueScope &jv, const tonlib_api::exportedUnencryptedKey &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "exportedUnencryptedKey"); + jo << ctie("data", ToJson(JsonBytes{object.data_})); +} void to_json(JsonValueScope &jv, const tonlib_api::fees &object) { auto jo = jv.enter_object(); jo << ctie("@type", "fees"); @@ -2029,6 +2385,68 @@ void to_json(JsonValueScope &jv, const tonlib_api::fees &object) { jo << ctie("gas_fee", ToJson(object.gas_fee_)); jo << ctie("fwd_fee", ToJson(object.fwd_fee_)); } +void to_json(JsonValueScope &jv, const tonlib_api::fullAccountState &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "fullAccountState"); + jo << ctie("balance", ToJson(JsonInt64{object.balance_})); + if (object.last_transaction_id_) { + jo << ctie("last_transaction_id", ToJson(object.last_transaction_id_)); + } + if (object.block_id_) { + jo << ctie("block_id", ToJson(object.block_id_)); + } + jo << ctie("sync_utime", ToJson(object.sync_utime_)); + if (object.account_state_) { + jo << ctie("account_state", ToJson(object.account_state_)); + } +} +void to_json(JsonValueScope &jv, const tonlib_api::InitialAccountState &object) { + tonlib_api::downcast_call(const_cast(object), [&jv](const auto &object) { to_json(jv, object); }); +} +void to_json(JsonValueScope &jv, const tonlib_api::raw_initialAccountState &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "raw.initialAccountState"); + jo << ctie("code", ToJson(JsonBytes{object.code_})); + jo << ctie("data", ToJson(JsonBytes{object.data_})); +} +void to_json(JsonValueScope &jv, const tonlib_api::testGiver_initialAccountState &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "testGiver.initialAccountState"); +} +void to_json(JsonValueScope &jv, const tonlib_api::testWallet_initialAccountState &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "testWallet.initialAccountState"); + jo << ctie("public_key", ToJson(object.public_key_)); +} +void to_json(JsonValueScope &jv, const tonlib_api::wallet_initialAccountState &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "wallet.initialAccountState"); + jo << ctie("public_key", ToJson(object.public_key_)); +} +void to_json(JsonValueScope &jv, const tonlib_api::wallet_v3_initialAccountState &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "wallet.v3.initialAccountState"); + jo << ctie("public_key", ToJson(object.public_key_)); + jo << ctie("wallet_id", ToJson(JsonInt64{object.wallet_id_})); +} +void to_json(JsonValueScope &jv, const tonlib_api::wallet_highload_v1_initialAccountState &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "wallet.highload.v1.initialAccountState"); + jo << ctie("public_key", ToJson(object.public_key_)); + jo << ctie("wallet_id", ToJson(JsonInt64{object.wallet_id_})); +} +void to_json(JsonValueScope &jv, const tonlib_api::wallet_highload_v2_initialAccountState &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "wallet.highload.v2.initialAccountState"); + jo << ctie("public_key", ToJson(object.public_key_)); + jo << ctie("wallet_id", ToJson(JsonInt64{object.wallet_id_})); +} +void to_json(JsonValueScope &jv, const tonlib_api::dns_initialAccountState &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "dns.initialAccountState"); + jo << ctie("public_key", ToJson(object.public_key_)); + jo << ctie("wallet_id", ToJson(JsonInt64{object.wallet_id_})); +} void to_json(JsonValueScope &jv, const tonlib_api::InputKey &object) { tonlib_api::downcast_call(const_cast(object), [&jv](const auto &object) { to_json(jv, object); }); } @@ -2103,12 +2521,6 @@ void to_json(JsonValueScope &jv, const tonlib_api::options &object) { jo << ctie("keystore_type", ToJson(object.keystore_type_)); } } -void to_json(JsonValueScope &jv, const tonlib_api::sendGramsResult &object) { - auto jo = jv.enter_object(); - jo << ctie("@type", "sendGramsResult"); - jo << ctie("sent_until", ToJson(object.sent_until_)); - jo << ctie("body_hash", ToJson(JsonBytes{object.body_hash_})); -} void to_json(JsonValueScope &jv, const tonlib_api::SyncState &object) { tonlib_api::downcast_call(const_cast(object), [&jv](const auto &object) { to_json(jv, object); }); } @@ -2147,50 +2559,80 @@ void to_json(JsonValueScope &jv, const tonlib_api::updateSyncState &object) { jo << ctie("sync_state", ToJson(object.sync_state_)); } } -void to_json(JsonValueScope &jv, const tonlib_api::generic_AccountState &object) { - tonlib_api::downcast_call(const_cast(object), [&jv](const auto &object) { to_json(jv, object); }); +void to_json(JsonValueScope &jv, const tonlib_api::dns_Action &object) { + tonlib_api::downcast_call(const_cast(object), [&jv](const auto &object) { to_json(jv, object); }); } -void to_json(JsonValueScope &jv, const tonlib_api::generic_accountStateRaw &object) { +void to_json(JsonValueScope &jv, const tonlib_api::dns_actionDeleteAll &object) { auto jo = jv.enter_object(); - jo << ctie("@type", "generic.accountStateRaw"); - if (object.account_state_) { - jo << ctie("account_state", ToJson(object.account_state_)); + jo << ctie("@type", "dns.actionDeleteAll"); +} +void to_json(JsonValueScope &jv, const tonlib_api::dns_actionDelete &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "dns.actionDelete"); + jo << ctie("name", ToJson(object.name_)); + jo << ctie("category", ToJson(object.category_)); +} +void to_json(JsonValueScope &jv, const tonlib_api::dns_actionSet &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "dns.actionSet"); + if (object.entry_) { + jo << ctie("entry", ToJson(object.entry_)); } } -void to_json(JsonValueScope &jv, const tonlib_api::generic_accountStateTestWallet &object) { +void to_json(JsonValueScope &jv, const tonlib_api::dns_entry &object) { auto jo = jv.enter_object(); - jo << ctie("@type", "generic.accountStateTestWallet"); - if (object.account_state_) { - jo << ctie("account_state", ToJson(object.account_state_)); + jo << ctie("@type", "dns.entry"); + jo << ctie("name", ToJson(object.name_)); + jo << ctie("category", ToJson(object.category_)); + if (object.entry_) { + jo << ctie("entry", ToJson(object.entry_)); } } -void to_json(JsonValueScope &jv, const tonlib_api::generic_accountStateWallet &object) { +void to_json(JsonValueScope &jv, const tonlib_api::dns_EntryData &object) { + tonlib_api::downcast_call(const_cast(object), [&jv](const auto &object) { to_json(jv, object); }); +} +void to_json(JsonValueScope &jv, const tonlib_api::dns_entryDataUnknown &object) { auto jo = jv.enter_object(); - jo << ctie("@type", "generic.accountStateWallet"); - if (object.account_state_) { - jo << ctie("account_state", ToJson(object.account_state_)); + jo << ctie("@type", "dns.entryDataUnknown"); + jo << ctie("bytes", ToJson(JsonBytes{object.bytes_})); +} +void to_json(JsonValueScope &jv, const tonlib_api::dns_entryDataText &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "dns.entryDataText"); + jo << ctie("text", ToJson(object.text_)); +} +void to_json(JsonValueScope &jv, const tonlib_api::dns_entryDataNextResolver &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "dns.entryDataNextResolver"); + if (object.resolver_) { + jo << ctie("resolver", ToJson(object.resolver_)); } } -void to_json(JsonValueScope &jv, const tonlib_api::generic_accountStateWalletV3 &object) { +void to_json(JsonValueScope &jv, const tonlib_api::dns_entryDataSmcAddress &object) { auto jo = jv.enter_object(); - jo << ctie("@type", "generic.accountStateWalletV3"); - if (object.account_state_) { - jo << ctie("account_state", ToJson(object.account_state_)); + jo << ctie("@type", "dns.entryDataSmcAddress"); + if (object.smc_address_) { + jo << ctie("smc_address", ToJson(object.smc_address_)); } } -void to_json(JsonValueScope &jv, const tonlib_api::generic_accountStateTestGiver &object) { +void to_json(JsonValueScope &jv, const tonlib_api::dns_entryDataAdnlAddress &object) { auto jo = jv.enter_object(); - jo << ctie("@type", "generic.accountStateTestGiver"); - if (object.account_state_) { - jo << ctie("account_state", ToJson(object.account_state_)); + jo << ctie("@type", "dns.entryDataAdnlAddress"); + if (object.adnl_address_) { + jo << ctie("adnl_address", ToJson(object.adnl_address_)); } } -void to_json(JsonValueScope &jv, const tonlib_api::generic_accountStateUninited &object) { +void to_json(JsonValueScope &jv, const tonlib_api::dns_resolved &object) { auto jo = jv.enter_object(); - jo << ctie("@type", "generic.accountStateUninited"); - if (object.account_state_) { - jo << ctie("account_state", ToJson(object.account_state_)); - } + jo << ctie("@type", "dns.resolved"); + jo << ctie("entries", ToJson(object.entries_)); +} +void to_json(JsonValueScope &jv, const tonlib_api::ton_blockId &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "ton.blockId"); + jo << ctie("workchain", ToJson(object.workchain_)); + jo << ctie("shard", ToJson(JsonInt64{object.shard_})); + jo << ctie("seqno", ToJson(object.seqno_)); } void to_json(JsonValueScope &jv, const tonlib_api::internal_transactionId &object) { auto jo = jv.enter_object(); @@ -2205,10 +2647,56 @@ void to_json(JsonValueScope &jv, const tonlib_api::liteServer_info &object) { jo << ctie("version", ToJson(object.version_)); jo << ctie("capabilities", ToJson(JsonInt64{object.capabilities_})); } +void to_json(JsonValueScope &jv, const tonlib_api::msg_Data &object) { + tonlib_api::downcast_call(const_cast(object), [&jv](const auto &object) { to_json(jv, object); }); +} +void to_json(JsonValueScope &jv, const tonlib_api::msg_dataRaw &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "msg.dataRaw"); + jo << ctie("body", ToJson(JsonBytes{object.body_})); +} +void to_json(JsonValueScope &jv, const tonlib_api::msg_dataText &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "msg.dataText"); + jo << ctie("text", ToJson(JsonBytes{object.text_})); +} +void to_json(JsonValueScope &jv, const tonlib_api::msg_dataDecryptedText &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "msg.dataDecryptedText"); + jo << ctie("text", ToJson(JsonBytes{object.text_})); +} +void to_json(JsonValueScope &jv, const tonlib_api::msg_dataEncryptedText &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "msg.dataEncryptedText"); + jo << ctie("text", ToJson(JsonBytes{object.text_})); +} +void to_json(JsonValueScope &jv, const tonlib_api::msg_dataArray &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "msg.dataArray"); + jo << ctie("elements", ToJson(object.elements_)); +} +void to_json(JsonValueScope &jv, const tonlib_api::msg_message &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "msg.message"); + if (object.destination_) { + jo << ctie("destination", ToJson(object.destination_)); + } + jo << ctie("amount", ToJson(JsonInt64{object.amount_})); + if (object.data_) { + jo << ctie("data", ToJson(object.data_)); + } +} void to_json(JsonValueScope &jv, const tonlib_api::options_configInfo &object) { auto jo = jv.enter_object(); jo << ctie("@type", "options.configInfo"); - jo << ctie("default_wallet_id", ToJson(object.default_wallet_id_)); + jo << ctie("default_wallet_id", ToJson(JsonInt64{object.default_wallet_id_})); +} +void to_json(JsonValueScope &jv, const tonlib_api::options_info &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "options.info"); + if (object.config_info_) { + jo << ctie("config_info", ToJson(object.config_info_)); + } } void to_json(JsonValueScope &jv, const tonlib_api::query_fees &object) { auto jo = jv.enter_object(); @@ -2216,9 +2704,7 @@ void to_json(JsonValueScope &jv, const tonlib_api::query_fees &object) { if (object.source_fees_) { jo << ctie("source_fees", ToJson(object.source_fees_)); } - if (object.destination_fees_) { - jo << ctie("destination_fees", ToJson(object.destination_fees_)); - } + jo << ctie("destination_fees", ToJson(object.destination_fees_)); } void to_json(JsonValueScope &jv, const tonlib_api::query_info &object) { auto jo = jv.enter_object(); @@ -2227,24 +2713,21 @@ void to_json(JsonValueScope &jv, const tonlib_api::query_info &object) { jo << ctie("valid_until", ToJson(object.valid_until_)); jo << ctie("body_hash", ToJson(JsonBytes{object.body_hash_})); } -void to_json(JsonValueScope &jv, const tonlib_api::raw_accountState &object) { +void to_json(JsonValueScope &jv, const tonlib_api::raw_fullAccountState &object) { auto jo = jv.enter_object(); - jo << ctie("@type", "raw.accountState"); + jo << ctie("@type", "raw.fullAccountState"); jo << ctie("balance", ToJson(JsonInt64{object.balance_})); jo << ctie("code", ToJson(JsonBytes{object.code_})); jo << ctie("data", ToJson(JsonBytes{object.data_})); if (object.last_transaction_id_) { jo << ctie("last_transaction_id", ToJson(object.last_transaction_id_)); } + if (object.block_id_) { + jo << ctie("block_id", ToJson(object.block_id_)); + } jo << ctie("frozen_hash", ToJson(JsonBytes{object.frozen_hash_})); jo << ctie("sync_utime", ToJson(object.sync_utime_)); } -void to_json(JsonValueScope &jv, const tonlib_api::raw_initialAccountState &object) { - auto jo = jv.enter_object(); - jo << ctie("@type", "raw.initialAccountState"); - jo << ctie("code", ToJson(JsonBytes{object.code_})); - jo << ctie("data", ToJson(JsonBytes{object.data_})); -} void to_json(JsonValueScope &jv, const tonlib_api::raw_message &object) { auto jo = jv.enter_object(); jo << ctie("@type", "raw.message"); @@ -2255,7 +2738,9 @@ void to_json(JsonValueScope &jv, const tonlib_api::raw_message &object) { jo << ctie("ihr_fee", ToJson(JsonInt64{object.ihr_fee_})); jo << ctie("created_lt", ToJson(JsonInt64{object.created_lt_})); jo << ctie("body_hash", ToJson(JsonBytes{object.body_hash_})); - jo << ctie("message", ToJson(JsonBytes{object.message_})); + if (object.msg_data_) { + jo << ctie("msg_data", ToJson(object.msg_data_)); + } } void to_json(JsonValueScope &jv, const tonlib_api::raw_transaction &object) { auto jo = jv.enter_object(); @@ -2306,35 +2791,24 @@ void to_json(JsonValueScope &jv, const tonlib_api::smc_runResult &object) { jo << ctie("stack", ToJson(object.stack_)); jo << ctie("exit_code", ToJson(object.exit_code_)); } -void to_json(JsonValueScope &jv, const tonlib_api::testGiver_accountState &object) { +void to_json(JsonValueScope &jv, const tonlib_api::ton_blockIdExt &object) { auto jo = jv.enter_object(); - jo << ctie("@type", "testGiver.accountState"); - jo << ctie("balance", ToJson(JsonInt64{object.balance_})); + jo << ctie("@type", "ton.blockIdExt"); + jo << ctie("workchain", ToJson(object.workchain_)); + jo << ctie("shard", ToJson(JsonInt64{object.shard_})); jo << ctie("seqno", ToJson(object.seqno_)); - if (object.last_transaction_id_) { - jo << ctie("last_transaction_id", ToJson(object.last_transaction_id_)); - } - jo << ctie("sync_utime", ToJson(object.sync_utime_)); -} -void to_json(JsonValueScope &jv, const tonlib_api::testWallet_accountState &object) { - auto jo = jv.enter_object(); - jo << ctie("@type", "testWallet.accountState"); - jo << ctie("balance", ToJson(JsonInt64{object.balance_})); - jo << ctie("seqno", ToJson(object.seqno_)); - if (object.last_transaction_id_) { - jo << ctie("last_transaction_id", ToJson(object.last_transaction_id_)); - } - jo << ctie("sync_utime", ToJson(object.sync_utime_)); -} -void to_json(JsonValueScope &jv, const tonlib_api::testWallet_initialAccountState &object) { - auto jo = jv.enter_object(); - jo << ctie("@type", "testWallet.initialAccountState"); - jo << ctie("public_key", ToJson(object.public_key_)); + jo << ctie("root_hash", ToJson(JsonBytes{object.root_hash_})); + jo << ctie("file_hash", ToJson(JsonBytes{object.file_hash_})); } void to_json(JsonValueScope &jv, const tonlib_api::tvm_cell &object) { auto jo = jv.enter_object(); jo << ctie("@type", "tvm.cell"); - jo << ctie("bytes", ToJson(object.bytes_)); + jo << ctie("bytes", ToJson(JsonBytes{object.bytes_})); +} +void to_json(JsonValueScope &jv, const tonlib_api::tvm_list &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "tvm.list"); + jo << ctie("elements", ToJson(object.elements_)); } void to_json(JsonValueScope &jv, const tonlib_api::tvm_numberDecimal &object) { auto jo = jv.enter_object(); @@ -2344,7 +2818,7 @@ void to_json(JsonValueScope &jv, const tonlib_api::tvm_numberDecimal &object) { void to_json(JsonValueScope &jv, const tonlib_api::tvm_slice &object) { auto jo = jv.enter_object(); jo << ctie("@type", "tvm.slice"); - jo << ctie("bytes", ToJson(object.bytes_)); + jo << ctie("bytes", ToJson(JsonBytes{object.bytes_})); } void to_json(JsonValueScope &jv, const tonlib_api::tvm_StackEntry &object) { tonlib_api::downcast_call(const_cast(object), [&jv](const auto &object) { to_json(jv, object); }); @@ -2370,51 +2844,28 @@ void to_json(JsonValueScope &jv, const tonlib_api::tvm_stackEntryNumber &object) jo << ctie("number", ToJson(object.number_)); } } +void to_json(JsonValueScope &jv, const tonlib_api::tvm_stackEntryTuple &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "tvm.stackEntryTuple"); + if (object.tuple_) { + jo << ctie("tuple", ToJson(object.tuple_)); + } +} +void to_json(JsonValueScope &jv, const tonlib_api::tvm_stackEntryList &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "tvm.stackEntryList"); + if (object.list_) { + jo << ctie("list", ToJson(object.list_)); + } +} void to_json(JsonValueScope &jv, const tonlib_api::tvm_stackEntryUnsupported &object) { auto jo = jv.enter_object(); jo << ctie("@type", "tvm.stackEntryUnsupported"); } -void to_json(JsonValueScope &jv, const tonlib_api::uninited_accountState &object) { +void to_json(JsonValueScope &jv, const tonlib_api::tvm_tuple &object) { auto jo = jv.enter_object(); - jo << ctie("@type", "uninited.accountState"); - jo << ctie("balance", ToJson(JsonInt64{object.balance_})); - if (object.last_transaction_id_) { - jo << ctie("last_transaction_id", ToJson(object.last_transaction_id_)); - } - jo << ctie("frozen_hash", ToJson(JsonBytes{object.frozen_hash_})); - jo << ctie("sync_utime", ToJson(object.sync_utime_)); -} -void to_json(JsonValueScope &jv, const tonlib_api::wallet_accountState &object) { - auto jo = jv.enter_object(); - jo << ctie("@type", "wallet.accountState"); - jo << ctie("balance", ToJson(JsonInt64{object.balance_})); - jo << ctie("seqno", ToJson(object.seqno_)); - if (object.last_transaction_id_) { - jo << ctie("last_transaction_id", ToJson(object.last_transaction_id_)); - } - jo << ctie("sync_utime", ToJson(object.sync_utime_)); -} -void to_json(JsonValueScope &jv, const tonlib_api::wallet_initialAccountState &object) { - auto jo = jv.enter_object(); - jo << ctie("@type", "wallet.initialAccountState"); - jo << ctie("public_key", ToJson(object.public_key_)); -} -void to_json(JsonValueScope &jv, const tonlib_api::wallet_v3_accountState &object) { - auto jo = jv.enter_object(); - jo << ctie("@type", "wallet.v3.accountState"); - jo << ctie("balance", ToJson(JsonInt64{object.balance_})); - jo << ctie("wallet_id", ToJson(object.wallet_id_)); - jo << ctie("seqno", ToJson(object.seqno_)); - if (object.last_transaction_id_) { - jo << ctie("last_transaction_id", ToJson(object.last_transaction_id_)); - } - jo << ctie("sync_utime", ToJson(object.sync_utime_)); -} -void to_json(JsonValueScope &jv, const tonlib_api::wallet_v3_initialAccountState &object) { - auto jo = jv.enter_object(); - jo << ctie("@type", "wallet.v3.initialAccountState"); - jo << ctie("public_key", ToJson(object.public_key_)); - jo << ctie("wallet_id", ToJson(object.wallet_id_)); + jo << ctie("@type", "tvm.tuple"); + jo << ctie("elements", ToJson(object.elements_)); } void to_json(JsonValueScope &jv, const tonlib_api::addLogMessage &object) { auto jo = jv.enter_object(); @@ -2441,6 +2892,20 @@ void to_json(JsonValueScope &jv, const tonlib_api::createNewKey &object) { jo << ctie("mnemonic_password", ToJson(JsonBytes{object.mnemonic_password_})); jo << ctie("random_extra_seed", ToJson(JsonBytes{object.random_extra_seed_})); } +void to_json(JsonValueScope &jv, const tonlib_api::createQuery &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "createQuery"); + if (object.private_key_) { + jo << ctie("private_key", ToJson(object.private_key_)); + } + if (object.address_) { + jo << ctie("address", ToJson(object.address_)); + } + jo << ctie("timeout", ToJson(object.timeout_)); + if (object.action_) { + jo << ctie("action", ToJson(object.action_)); + } +} void to_json(JsonValueScope &jv, const tonlib_api::decrypt &object) { auto jo = jv.enter_object(); jo << ctie("@type", "decrypt"); @@ -2458,6 +2923,16 @@ void to_json(JsonValueScope &jv, const tonlib_api::deleteKey &object) { jo << ctie("key", ToJson(object.key_)); } } +void to_json(JsonValueScope &jv, const tonlib_api::dns_resolve &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "dns.resolve"); + if (object.account_address_) { + jo << ctie("account_address", ToJson(object.account_address_)); + } + jo << ctie("name", ToJson(object.name_)); + jo << ctie("category", ToJson(object.category_)); + jo << ctie("ttl", ToJson(object.ttl_)); +} void to_json(JsonValueScope &jv, const tonlib_api::encrypt &object) { auto jo = jv.enter_object(); jo << ctie("@type", "encrypt"); @@ -2487,47 +2962,28 @@ void to_json(JsonValueScope &jv, const tonlib_api::exportPemKey &object) { } jo << ctie("key_password", ToJson(JsonBytes{object.key_password_})); } -void to_json(JsonValueScope &jv, const tonlib_api::generic_createSendGramsQuery &object) { +void to_json(JsonValueScope &jv, const tonlib_api::exportUnencryptedKey &object) { auto jo = jv.enter_object(); - jo << ctie("@type", "generic.createSendGramsQuery"); - if (object.private_key_) { - jo << ctie("private_key", ToJson(object.private_key_)); + jo << ctie("@type", "exportUnencryptedKey"); + if (object.input_key_) { + jo << ctie("input_key", ToJson(object.input_key_)); } - if (object.source_) { - jo << ctie("source", ToJson(object.source_)); - } - if (object.destination_) { - jo << ctie("destination", ToJson(object.destination_)); - } - jo << ctie("amount", ToJson(JsonInt64{object.amount_})); - jo << ctie("timeout", ToJson(object.timeout_)); - jo << ctie("allow_send_to_uninited", ToJson(object.allow_send_to_uninited_)); - jo << ctie("message", ToJson(JsonBytes{object.message_})); } -void to_json(JsonValueScope &jv, const tonlib_api::generic_getAccountState &object) { +void to_json(JsonValueScope &jv, const tonlib_api::getAccountAddress &object) { auto jo = jv.enter_object(); - jo << ctie("@type", "generic.getAccountState"); + jo << ctie("@type", "getAccountAddress"); + if (object.initial_account_state_) { + jo << ctie("initial_account_state", ToJson(object.initial_account_state_)); + } + jo << ctie("revision", ToJson(object.revision_)); +} +void to_json(JsonValueScope &jv, const tonlib_api::getAccountState &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "getAccountState"); if (object.account_address_) { jo << ctie("account_address", ToJson(object.account_address_)); } } -void to_json(JsonValueScope &jv, const tonlib_api::generic_sendGrams &object) { - auto jo = jv.enter_object(); - jo << ctie("@type", "generic.sendGrams"); - if (object.private_key_) { - jo << ctie("private_key", ToJson(object.private_key_)); - } - if (object.source_) { - jo << ctie("source", ToJson(object.source_)); - } - if (object.destination_) { - jo << ctie("destination", ToJson(object.destination_)); - } - jo << ctie("amount", ToJson(JsonInt64{object.amount_})); - jo << ctie("timeout", ToJson(object.timeout_)); - jo << ctie("allow_send_to_uninited", ToJson(object.allow_send_to_uninited_)); - jo << ctie("message", ToJson(JsonBytes{object.message_})); -} void to_json(JsonValueScope &jv, const tonlib_api::getBip39Hints &object) { auto jo = jv.enter_object(); jo << ctie("@type", "getBip39Hints"); @@ -2550,6 +3006,13 @@ void to_json(JsonValueScope &jv, const tonlib_api::getLogVerbosityLevel &object) auto jo = jv.enter_object(); jo << ctie("@type", "getLogVerbosityLevel"); } +void to_json(JsonValueScope &jv, const tonlib_api::guessAccountRevision &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "guessAccountRevision"); + if (object.initial_account_state_) { + jo << ctie("initial_account_state", ToJson(object.initial_account_state_)); + } +} void to_json(JsonValueScope &jv, const tonlib_api::importEncryptedKey &object) { auto jo = jv.enter_object(); jo << ctie("@type", "importEncryptedKey"); @@ -2577,6 +3040,14 @@ void to_json(JsonValueScope &jv, const tonlib_api::importPemKey &object) { jo << ctie("exported_key", ToJson(object.exported_key_)); } } +void to_json(JsonValueScope &jv, const tonlib_api::importUnencryptedKey &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "importUnencryptedKey"); + jo << ctie("local_password", ToJson(JsonBytes{object.local_password_})); + if (object.exported_unencrypted_key_) { + jo << ctie("exported_unencrypted_key", ToJson(object.exported_unencrypted_key_)); + } +} void to_json(JsonValueScope &jv, const tonlib_api::init &object) { auto jo = jv.enter_object(); jo << ctie("@type", "init"); @@ -2595,6 +3066,16 @@ void to_json(JsonValueScope &jv, const tonlib_api::liteServer_getInfo &object) { auto jo = jv.enter_object(); jo << ctie("@type", "liteServer.getInfo"); } +void to_json(JsonValueScope &jv, const tonlib_api::msg_decrypt &object) { + auto jo = jv.enter_object(); + jo << ctie("@type", "msg.decrypt"); + if (object.input_key_) { + jo << ctie("input_key", ToJson(object.input_key_)); + } + if (object.data_) { + jo << ctie("data", ToJson(object.data_)); + } +} void to_json(JsonValueScope &jv, const tonlib_api::onLiteServerQueryError &object) { auto jo = jv.enter_object(); jo << ctie("@type", "onLiteServerQueryError"); @@ -2670,13 +3151,6 @@ void to_json(JsonValueScope &jv, const tonlib_api::raw_createQuery &object) { jo << ctie("init_data", ToJson(JsonBytes{object.init_data_})); jo << ctie("body", ToJson(JsonBytes{object.body_})); } -void to_json(JsonValueScope &jv, const tonlib_api::raw_getAccountAddress &object) { - auto jo = jv.enter_object(); - jo << ctie("@type", "raw.getAccountAddress"); - if (object.initital_account_state_) { - jo << ctie("initital_account_state", ToJson(object.initital_account_state_)); - } -} void to_json(JsonValueScope &jv, const tonlib_api::raw_getAccountState &object) { auto jo = jv.enter_object(); jo << ctie("@type", "raw.getAccountState"); @@ -2687,6 +3161,9 @@ void to_json(JsonValueScope &jv, const tonlib_api::raw_getAccountState &object) void to_json(JsonValueScope &jv, const tonlib_api::raw_getTransactions &object) { auto jo = jv.enter_object(); jo << ctie("@type", "raw.getTransactions"); + if (object.private_key_) { + jo << ctie("private_key", ToJson(object.private_key_)); + } if (object.account_address_) { jo << ctie("account_address", ToJson(object.account_address_)); } @@ -2757,104 +3234,18 @@ void to_json(JsonValueScope &jv, const tonlib_api::sync &object) { auto jo = jv.enter_object(); jo << ctie("@type", "sync"); } -void to_json(JsonValueScope &jv, const tonlib_api::testGiver_getAccountAddress &object) { - auto jo = jv.enter_object(); - jo << ctie("@type", "testGiver.getAccountAddress"); -} -void to_json(JsonValueScope &jv, const tonlib_api::testGiver_getAccountState &object) { - auto jo = jv.enter_object(); - jo << ctie("@type", "testGiver.getAccountState"); -} -void to_json(JsonValueScope &jv, const tonlib_api::testGiver_sendGrams &object) { - auto jo = jv.enter_object(); - jo << ctie("@type", "testGiver.sendGrams"); - if (object.destination_) { - jo << ctie("destination", ToJson(object.destination_)); - } - jo << ctie("seqno", ToJson(object.seqno_)); - jo << ctie("amount", ToJson(JsonInt64{object.amount_})); - jo << ctie("message", ToJson(JsonBytes{object.message_})); -} -void to_json(JsonValueScope &jv, const tonlib_api::testWallet_getAccountAddress &object) { - auto jo = jv.enter_object(); - jo << ctie("@type", "testWallet.getAccountAddress"); - if (object.initital_account_state_) { - jo << ctie("initital_account_state", ToJson(object.initital_account_state_)); - } -} -void to_json(JsonValueScope &jv, const tonlib_api::testWallet_getAccountState &object) { - auto jo = jv.enter_object(); - jo << ctie("@type", "testWallet.getAccountState"); - if (object.account_address_) { - jo << ctie("account_address", ToJson(object.account_address_)); - } -} -void to_json(JsonValueScope &jv, const tonlib_api::testWallet_init &object) { - auto jo = jv.enter_object(); - jo << ctie("@type", "testWallet.init"); - if (object.private_key_) { - jo << ctie("private_key", ToJson(object.private_key_)); - } -} -void to_json(JsonValueScope &jv, const tonlib_api::testWallet_sendGrams &object) { - auto jo = jv.enter_object(); - jo << ctie("@type", "testWallet.sendGrams"); - if (object.private_key_) { - jo << ctie("private_key", ToJson(object.private_key_)); - } - if (object.destination_) { - jo << ctie("destination", ToJson(object.destination_)); - } - jo << ctie("seqno", ToJson(object.seqno_)); - jo << ctie("amount", ToJson(JsonInt64{object.amount_})); - jo << ctie("message", ToJson(JsonBytes{object.message_})); -} void to_json(JsonValueScope &jv, const tonlib_api::unpackAccountAddress &object) { auto jo = jv.enter_object(); jo << ctie("@type", "unpackAccountAddress"); jo << ctie("account_address", ToJson(object.account_address_)); } -void to_json(JsonValueScope &jv, const tonlib_api::wallet_getAccountAddress &object) { +void to_json(JsonValueScope &jv, const tonlib_api::withBlock &object) { auto jo = jv.enter_object(); - jo << ctie("@type", "wallet.getAccountAddress"); - if (object.initital_account_state_) { - jo << ctie("initital_account_state", ToJson(object.initital_account_state_)); - } -} -void to_json(JsonValueScope &jv, const tonlib_api::wallet_getAccountState &object) { - auto jo = jv.enter_object(); - jo << ctie("@type", "wallet.getAccountState"); - if (object.account_address_) { - jo << ctie("account_address", ToJson(object.account_address_)); - } -} -void to_json(JsonValueScope &jv, const tonlib_api::wallet_init &object) { - auto jo = jv.enter_object(); - jo << ctie("@type", "wallet.init"); - if (object.private_key_) { - jo << ctie("private_key", ToJson(object.private_key_)); - } -} -void to_json(JsonValueScope &jv, const tonlib_api::wallet_sendGrams &object) { - auto jo = jv.enter_object(); - jo << ctie("@type", "wallet.sendGrams"); - if (object.private_key_) { - jo << ctie("private_key", ToJson(object.private_key_)); - } - if (object.destination_) { - jo << ctie("destination", ToJson(object.destination_)); - } - jo << ctie("seqno", ToJson(object.seqno_)); - jo << ctie("valid_until", ToJson(object.valid_until_)); - jo << ctie("amount", ToJson(JsonInt64{object.amount_})); - jo << ctie("message", ToJson(JsonBytes{object.message_})); -} -void to_json(JsonValueScope &jv, const tonlib_api::wallet_v3_getAccountAddress &object) { - auto jo = jv.enter_object(); - jo << ctie("@type", "wallet.v3.getAccountAddress"); - if (object.initital_account_state_) { - jo << ctie("initital_account_state", ToJson(object.initital_account_state_)); + jo << ctie("@type", "withBlock"); + if (object.id_) { + jo << ctie("id", ToJson(object.id_)); } + jo << ctie("function", ToJson(object.function_)); } } // namespace tonlib_api } // namespace ton diff --git a/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api_json.h b/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api_json.h index d57816d82e..4c1c430fc7 100644 --- a/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api_json.h +++ b/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api_json.h @@ -11,17 +11,36 @@ namespace ton { namespace tonlib_api{ using namespace td; +Result tl_constructor_from_string(tonlib_api::AccountState *object, const std::string &str); +Result tl_constructor_from_string(tonlib_api::Action *object, const std::string &str); +Result tl_constructor_from_string(tonlib_api::InitialAccountState *object, const std::string &str); Result tl_constructor_from_string(tonlib_api::InputKey *object, const std::string &str); Result tl_constructor_from_string(tonlib_api::KeyStoreType *object, const std::string &str); Result tl_constructor_from_string(tonlib_api::LogStream *object, const std::string &str); Result tl_constructor_from_string(tonlib_api::SyncState *object, const std::string &str); Result tl_constructor_from_string(tonlib_api::Update *object, const std::string &str); -Result tl_constructor_from_string(tonlib_api::generic_AccountState *object, const std::string &str); +Result tl_constructor_from_string(tonlib_api::dns_Action *object, const std::string &str); +Result tl_constructor_from_string(tonlib_api::dns_EntryData *object, const std::string &str); +Result tl_constructor_from_string(tonlib_api::msg_Data *object, const std::string &str); Result tl_constructor_from_string(tonlib_api::smc_MethodId *object, const std::string &str); Result tl_constructor_from_string(tonlib_api::tvm_StackEntry *object, const std::string &str); Result tl_constructor_from_string(tonlib_api::Object *object, const std::string &str); Result tl_constructor_from_string(tonlib_api::Function *object, const std::string &str); Status from_json(tonlib_api::accountAddress &to, JsonObject &from); +Status from_json(tonlib_api::accountRevisionList &to, JsonObject &from); +Status from_json(tonlib_api::raw_accountState &to, JsonObject &from); +Status from_json(tonlib_api::testWallet_accountState &to, JsonObject &from); +Status from_json(tonlib_api::wallet_accountState &to, JsonObject &from); +Status from_json(tonlib_api::wallet_v3_accountState &to, JsonObject &from); +Status from_json(tonlib_api::wallet_highload_v1_accountState &to, JsonObject &from); +Status from_json(tonlib_api::wallet_highload_v2_accountState &to, JsonObject &from); +Status from_json(tonlib_api::testGiver_accountState &to, JsonObject &from); +Status from_json(tonlib_api::dns_accountState &to, JsonObject &from); +Status from_json(tonlib_api::uninited_accountState &to, JsonObject &from); +Status from_json(tonlib_api::actionNoop &to, JsonObject &from); +Status from_json(tonlib_api::actionMsg &to, JsonObject &from); +Status from_json(tonlib_api::actionDns &to, JsonObject &from); +Status from_json(tonlib_api::adnlAddress &to, JsonObject &from); Status from_json(tonlib_api::bip39Hints &to, JsonObject &from); Status from_json(tonlib_api::config &to, JsonObject &from); Status from_json(tonlib_api::data &to, JsonObject &from); @@ -29,7 +48,17 @@ Status from_json(tonlib_api::error &to, JsonObject &from); Status from_json(tonlib_api::exportedEncryptedKey &to, JsonObject &from); Status from_json(tonlib_api::exportedKey &to, JsonObject &from); Status from_json(tonlib_api::exportedPemKey &to, JsonObject &from); +Status from_json(tonlib_api::exportedUnencryptedKey &to, JsonObject &from); Status from_json(tonlib_api::fees &to, JsonObject &from); +Status from_json(tonlib_api::fullAccountState &to, JsonObject &from); +Status from_json(tonlib_api::raw_initialAccountState &to, JsonObject &from); +Status from_json(tonlib_api::testGiver_initialAccountState &to, JsonObject &from); +Status from_json(tonlib_api::testWallet_initialAccountState &to, JsonObject &from); +Status from_json(tonlib_api::wallet_initialAccountState &to, JsonObject &from); +Status from_json(tonlib_api::wallet_v3_initialAccountState &to, JsonObject &from); +Status from_json(tonlib_api::wallet_highload_v1_initialAccountState &to, JsonObject &from); +Status from_json(tonlib_api::wallet_highload_v2_initialAccountState &to, JsonObject &from); +Status from_json(tonlib_api::dns_initialAccountState &to, JsonObject &from); Status from_json(tonlib_api::inputKeyRegular &to, JsonObject &from); Status from_json(tonlib_api::inputKeyFake &to, JsonObject &from); Status from_json(tonlib_api::key &to, JsonObject &from); @@ -42,25 +71,35 @@ Status from_json(tonlib_api::logTags &to, JsonObject &from); Status from_json(tonlib_api::logVerbosityLevel &to, JsonObject &from); Status from_json(tonlib_api::ok &to, JsonObject &from); Status from_json(tonlib_api::options &to, JsonObject &from); -Status from_json(tonlib_api::sendGramsResult &to, JsonObject &from); Status from_json(tonlib_api::syncStateDone &to, JsonObject &from); Status from_json(tonlib_api::syncStateInProgress &to, JsonObject &from); Status from_json(tonlib_api::unpackedAccountAddress &to, JsonObject &from); Status from_json(tonlib_api::updateSendLiteServerQuery &to, JsonObject &from); Status from_json(tonlib_api::updateSyncState &to, JsonObject &from); -Status from_json(tonlib_api::generic_accountStateRaw &to, JsonObject &from); -Status from_json(tonlib_api::generic_accountStateTestWallet &to, JsonObject &from); -Status from_json(tonlib_api::generic_accountStateWallet &to, JsonObject &from); -Status from_json(tonlib_api::generic_accountStateWalletV3 &to, JsonObject &from); -Status from_json(tonlib_api::generic_accountStateTestGiver &to, JsonObject &from); -Status from_json(tonlib_api::generic_accountStateUninited &to, JsonObject &from); +Status from_json(tonlib_api::dns_actionDeleteAll &to, JsonObject &from); +Status from_json(tonlib_api::dns_actionDelete &to, JsonObject &from); +Status from_json(tonlib_api::dns_actionSet &to, JsonObject &from); +Status from_json(tonlib_api::dns_entry &to, JsonObject &from); +Status from_json(tonlib_api::dns_entryDataUnknown &to, JsonObject &from); +Status from_json(tonlib_api::dns_entryDataText &to, JsonObject &from); +Status from_json(tonlib_api::dns_entryDataNextResolver &to, JsonObject &from); +Status from_json(tonlib_api::dns_entryDataSmcAddress &to, JsonObject &from); +Status from_json(tonlib_api::dns_entryDataAdnlAddress &to, JsonObject &from); +Status from_json(tonlib_api::dns_resolved &to, JsonObject &from); +Status from_json(tonlib_api::ton_blockId &to, JsonObject &from); Status from_json(tonlib_api::internal_transactionId &to, JsonObject &from); Status from_json(tonlib_api::liteServer_info &to, JsonObject &from); +Status from_json(tonlib_api::msg_dataRaw &to, JsonObject &from); +Status from_json(tonlib_api::msg_dataText &to, JsonObject &from); +Status from_json(tonlib_api::msg_dataDecryptedText &to, JsonObject &from); +Status from_json(tonlib_api::msg_dataEncryptedText &to, JsonObject &from); +Status from_json(tonlib_api::msg_dataArray &to, JsonObject &from); +Status from_json(tonlib_api::msg_message &to, JsonObject &from); Status from_json(tonlib_api::options_configInfo &to, JsonObject &from); +Status from_json(tonlib_api::options_info &to, JsonObject &from); Status from_json(tonlib_api::query_fees &to, JsonObject &from); Status from_json(tonlib_api::query_info &to, JsonObject &from); -Status from_json(tonlib_api::raw_accountState &to, JsonObject &from); -Status from_json(tonlib_api::raw_initialAccountState &to, JsonObject &from); +Status from_json(tonlib_api::raw_fullAccountState &to, JsonObject &from); Status from_json(tonlib_api::raw_message &to, JsonObject &from); Status from_json(tonlib_api::raw_transaction &to, JsonObject &from); Status from_json(tonlib_api::raw_transactions &to, JsonObject &from); @@ -68,46 +107,48 @@ Status from_json(tonlib_api::smc_info &to, JsonObject &from); Status from_json(tonlib_api::smc_methodIdNumber &to, JsonObject &from); Status from_json(tonlib_api::smc_methodIdName &to, JsonObject &from); Status from_json(tonlib_api::smc_runResult &to, JsonObject &from); -Status from_json(tonlib_api::testGiver_accountState &to, JsonObject &from); -Status from_json(tonlib_api::testWallet_accountState &to, JsonObject &from); -Status from_json(tonlib_api::testWallet_initialAccountState &to, JsonObject &from); +Status from_json(tonlib_api::ton_blockIdExt &to, JsonObject &from); Status from_json(tonlib_api::tvm_cell &to, JsonObject &from); +Status from_json(tonlib_api::tvm_list &to, JsonObject &from); Status from_json(tonlib_api::tvm_numberDecimal &to, JsonObject &from); Status from_json(tonlib_api::tvm_slice &to, JsonObject &from); Status from_json(tonlib_api::tvm_stackEntrySlice &to, JsonObject &from); Status from_json(tonlib_api::tvm_stackEntryCell &to, JsonObject &from); Status from_json(tonlib_api::tvm_stackEntryNumber &to, JsonObject &from); +Status from_json(tonlib_api::tvm_stackEntryTuple &to, JsonObject &from); +Status from_json(tonlib_api::tvm_stackEntryList &to, JsonObject &from); Status from_json(tonlib_api::tvm_stackEntryUnsupported &to, JsonObject &from); -Status from_json(tonlib_api::uninited_accountState &to, JsonObject &from); -Status from_json(tonlib_api::wallet_accountState &to, JsonObject &from); -Status from_json(tonlib_api::wallet_initialAccountState &to, JsonObject &from); -Status from_json(tonlib_api::wallet_v3_accountState &to, JsonObject &from); -Status from_json(tonlib_api::wallet_v3_initialAccountState &to, JsonObject &from); +Status from_json(tonlib_api::tvm_tuple &to, JsonObject &from); Status from_json(tonlib_api::addLogMessage &to, JsonObject &from); Status from_json(tonlib_api::changeLocalPassword &to, JsonObject &from); Status from_json(tonlib_api::close &to, JsonObject &from); Status from_json(tonlib_api::createNewKey &to, JsonObject &from); +Status from_json(tonlib_api::createQuery &to, JsonObject &from); Status from_json(tonlib_api::decrypt &to, JsonObject &from); Status from_json(tonlib_api::deleteAllKeys &to, JsonObject &from); Status from_json(tonlib_api::deleteKey &to, JsonObject &from); +Status from_json(tonlib_api::dns_resolve &to, JsonObject &from); Status from_json(tonlib_api::encrypt &to, JsonObject &from); Status from_json(tonlib_api::exportEncryptedKey &to, JsonObject &from); Status from_json(tonlib_api::exportKey &to, JsonObject &from); Status from_json(tonlib_api::exportPemKey &to, JsonObject &from); -Status from_json(tonlib_api::generic_createSendGramsQuery &to, JsonObject &from); -Status from_json(tonlib_api::generic_getAccountState &to, JsonObject &from); -Status from_json(tonlib_api::generic_sendGrams &to, JsonObject &from); +Status from_json(tonlib_api::exportUnencryptedKey &to, JsonObject &from); +Status from_json(tonlib_api::getAccountAddress &to, JsonObject &from); +Status from_json(tonlib_api::getAccountState &to, JsonObject &from); Status from_json(tonlib_api::getBip39Hints &to, JsonObject &from); Status from_json(tonlib_api::getLogStream &to, JsonObject &from); Status from_json(tonlib_api::getLogTagVerbosityLevel &to, JsonObject &from); Status from_json(tonlib_api::getLogTags &to, JsonObject &from); Status from_json(tonlib_api::getLogVerbosityLevel &to, JsonObject &from); +Status from_json(tonlib_api::guessAccountRevision &to, JsonObject &from); Status from_json(tonlib_api::importEncryptedKey &to, JsonObject &from); Status from_json(tonlib_api::importKey &to, JsonObject &from); Status from_json(tonlib_api::importPemKey &to, JsonObject &from); +Status from_json(tonlib_api::importUnencryptedKey &to, JsonObject &from); Status from_json(tonlib_api::init &to, JsonObject &from); Status from_json(tonlib_api::kdf &to, JsonObject &from); Status from_json(tonlib_api::liteServer_getInfo &to, JsonObject &from); +Status from_json(tonlib_api::msg_decrypt &to, JsonObject &from); Status from_json(tonlib_api::onLiteServerQueryError &to, JsonObject &from); Status from_json(tonlib_api::onLiteServerQueryResult &to, JsonObject &from); Status from_json(tonlib_api::options_setConfig &to, JsonObject &from); @@ -119,7 +160,6 @@ Status from_json(tonlib_api::query_getInfo &to, JsonObject &from); Status from_json(tonlib_api::query_send &to, JsonObject &from); Status from_json(tonlib_api::raw_createAndSendMessage &to, JsonObject &from); Status from_json(tonlib_api::raw_createQuery &to, JsonObject &from); -Status from_json(tonlib_api::raw_getAccountAddress &to, JsonObject &from); Status from_json(tonlib_api::raw_getAccountState &to, JsonObject &from); Status from_json(tonlib_api::raw_getTransactions &to, JsonObject &from); Status from_json(tonlib_api::raw_sendMessage &to, JsonObject &from); @@ -133,20 +173,25 @@ Status from_json(tonlib_api::smc_getState &to, JsonObject &from); Status from_json(tonlib_api::smc_load &to, JsonObject &from); Status from_json(tonlib_api::smc_runGetMethod &to, JsonObject &from); Status from_json(tonlib_api::sync &to, JsonObject &from); -Status from_json(tonlib_api::testGiver_getAccountAddress &to, JsonObject &from); -Status from_json(tonlib_api::testGiver_getAccountState &to, JsonObject &from); -Status from_json(tonlib_api::testGiver_sendGrams &to, JsonObject &from); -Status from_json(tonlib_api::testWallet_getAccountAddress &to, JsonObject &from); -Status from_json(tonlib_api::testWallet_getAccountState &to, JsonObject &from); -Status from_json(tonlib_api::testWallet_init &to, JsonObject &from); -Status from_json(tonlib_api::testWallet_sendGrams &to, JsonObject &from); Status from_json(tonlib_api::unpackAccountAddress &to, JsonObject &from); -Status from_json(tonlib_api::wallet_getAccountAddress &to, JsonObject &from); -Status from_json(tonlib_api::wallet_getAccountState &to, JsonObject &from); -Status from_json(tonlib_api::wallet_init &to, JsonObject &from); -Status from_json(tonlib_api::wallet_sendGrams &to, JsonObject &from); -Status from_json(tonlib_api::wallet_v3_getAccountAddress &to, JsonObject &from); +Status from_json(tonlib_api::withBlock &to, JsonObject &from); void to_json(JsonValueScope &jv, const tonlib_api::accountAddress &object); +void to_json(JsonValueScope &jv, const tonlib_api::accountRevisionList &object); +void to_json(JsonValueScope &jv, const tonlib_api::AccountState &object); +void to_json(JsonValueScope &jv, const tonlib_api::raw_accountState &object); +void to_json(JsonValueScope &jv, const tonlib_api::testWallet_accountState &object); +void to_json(JsonValueScope &jv, const tonlib_api::wallet_accountState &object); +void to_json(JsonValueScope &jv, const tonlib_api::wallet_v3_accountState &object); +void to_json(JsonValueScope &jv, const tonlib_api::wallet_highload_v1_accountState &object); +void to_json(JsonValueScope &jv, const tonlib_api::wallet_highload_v2_accountState &object); +void to_json(JsonValueScope &jv, const tonlib_api::testGiver_accountState &object); +void to_json(JsonValueScope &jv, const tonlib_api::dns_accountState &object); +void to_json(JsonValueScope &jv, const tonlib_api::uninited_accountState &object); +void to_json(JsonValueScope &jv, const tonlib_api::Action &object); +void to_json(JsonValueScope &jv, const tonlib_api::actionNoop &object); +void to_json(JsonValueScope &jv, const tonlib_api::actionMsg &object); +void to_json(JsonValueScope &jv, const tonlib_api::actionDns &object); +void to_json(JsonValueScope &jv, const tonlib_api::adnlAddress &object); void to_json(JsonValueScope &jv, const tonlib_api::bip39Hints &object); void to_json(JsonValueScope &jv, const tonlib_api::config &object); void to_json(JsonValueScope &jv, const tonlib_api::data &object); @@ -154,7 +199,18 @@ void to_json(JsonValueScope &jv, const tonlib_api::error &object); void to_json(JsonValueScope &jv, const tonlib_api::exportedEncryptedKey &object); void to_json(JsonValueScope &jv, const tonlib_api::exportedKey &object); void to_json(JsonValueScope &jv, const tonlib_api::exportedPemKey &object); +void to_json(JsonValueScope &jv, const tonlib_api::exportedUnencryptedKey &object); void to_json(JsonValueScope &jv, const tonlib_api::fees &object); +void to_json(JsonValueScope &jv, const tonlib_api::fullAccountState &object); +void to_json(JsonValueScope &jv, const tonlib_api::InitialAccountState &object); +void to_json(JsonValueScope &jv, const tonlib_api::raw_initialAccountState &object); +void to_json(JsonValueScope &jv, const tonlib_api::testGiver_initialAccountState &object); +void to_json(JsonValueScope &jv, const tonlib_api::testWallet_initialAccountState &object); +void to_json(JsonValueScope &jv, const tonlib_api::wallet_initialAccountState &object); +void to_json(JsonValueScope &jv, const tonlib_api::wallet_v3_initialAccountState &object); +void to_json(JsonValueScope &jv, const tonlib_api::wallet_highload_v1_initialAccountState &object); +void to_json(JsonValueScope &jv, const tonlib_api::wallet_highload_v2_initialAccountState &object); +void to_json(JsonValueScope &jv, const tonlib_api::dns_initialAccountState &object); void to_json(JsonValueScope &jv, const tonlib_api::InputKey &object); void to_json(JsonValueScope &jv, const tonlib_api::inputKeyRegular &object); void to_json(JsonValueScope &jv, const tonlib_api::inputKeyFake &object); @@ -170,7 +226,6 @@ void to_json(JsonValueScope &jv, const tonlib_api::logTags &object); void to_json(JsonValueScope &jv, const tonlib_api::logVerbosityLevel &object); void to_json(JsonValueScope &jv, const tonlib_api::ok &object); void to_json(JsonValueScope &jv, const tonlib_api::options &object); -void to_json(JsonValueScope &jv, const tonlib_api::sendGramsResult &object); void to_json(JsonValueScope &jv, const tonlib_api::SyncState &object); void to_json(JsonValueScope &jv, const tonlib_api::syncStateDone &object); void to_json(JsonValueScope &jv, const tonlib_api::syncStateInProgress &object); @@ -178,20 +233,33 @@ void to_json(JsonValueScope &jv, const tonlib_api::unpackedAccountAddress &objec void to_json(JsonValueScope &jv, const tonlib_api::Update &object); void to_json(JsonValueScope &jv, const tonlib_api::updateSendLiteServerQuery &object); void to_json(JsonValueScope &jv, const tonlib_api::updateSyncState &object); -void to_json(JsonValueScope &jv, const tonlib_api::generic_AccountState &object); -void to_json(JsonValueScope &jv, const tonlib_api::generic_accountStateRaw &object); -void to_json(JsonValueScope &jv, const tonlib_api::generic_accountStateTestWallet &object); -void to_json(JsonValueScope &jv, const tonlib_api::generic_accountStateWallet &object); -void to_json(JsonValueScope &jv, const tonlib_api::generic_accountStateWalletV3 &object); -void to_json(JsonValueScope &jv, const tonlib_api::generic_accountStateTestGiver &object); -void to_json(JsonValueScope &jv, const tonlib_api::generic_accountStateUninited &object); +void to_json(JsonValueScope &jv, const tonlib_api::dns_Action &object); +void to_json(JsonValueScope &jv, const tonlib_api::dns_actionDeleteAll &object); +void to_json(JsonValueScope &jv, const tonlib_api::dns_actionDelete &object); +void to_json(JsonValueScope &jv, const tonlib_api::dns_actionSet &object); +void to_json(JsonValueScope &jv, const tonlib_api::dns_entry &object); +void to_json(JsonValueScope &jv, const tonlib_api::dns_EntryData &object); +void to_json(JsonValueScope &jv, const tonlib_api::dns_entryDataUnknown &object); +void to_json(JsonValueScope &jv, const tonlib_api::dns_entryDataText &object); +void to_json(JsonValueScope &jv, const tonlib_api::dns_entryDataNextResolver &object); +void to_json(JsonValueScope &jv, const tonlib_api::dns_entryDataSmcAddress &object); +void to_json(JsonValueScope &jv, const tonlib_api::dns_entryDataAdnlAddress &object); +void to_json(JsonValueScope &jv, const tonlib_api::dns_resolved &object); +void to_json(JsonValueScope &jv, const tonlib_api::ton_blockId &object); void to_json(JsonValueScope &jv, const tonlib_api::internal_transactionId &object); void to_json(JsonValueScope &jv, const tonlib_api::liteServer_info &object); +void to_json(JsonValueScope &jv, const tonlib_api::msg_Data &object); +void to_json(JsonValueScope &jv, const tonlib_api::msg_dataRaw &object); +void to_json(JsonValueScope &jv, const tonlib_api::msg_dataText &object); +void to_json(JsonValueScope &jv, const tonlib_api::msg_dataDecryptedText &object); +void to_json(JsonValueScope &jv, const tonlib_api::msg_dataEncryptedText &object); +void to_json(JsonValueScope &jv, const tonlib_api::msg_dataArray &object); +void to_json(JsonValueScope &jv, const tonlib_api::msg_message &object); void to_json(JsonValueScope &jv, const tonlib_api::options_configInfo &object); +void to_json(JsonValueScope &jv, const tonlib_api::options_info &object); void to_json(JsonValueScope &jv, const tonlib_api::query_fees &object); void to_json(JsonValueScope &jv, const tonlib_api::query_info &object); -void to_json(JsonValueScope &jv, const tonlib_api::raw_accountState &object); -void to_json(JsonValueScope &jv, const tonlib_api::raw_initialAccountState &object); +void to_json(JsonValueScope &jv, const tonlib_api::raw_fullAccountState &object); void to_json(JsonValueScope &jv, const tonlib_api::raw_message &object); void to_json(JsonValueScope &jv, const tonlib_api::raw_transaction &object); void to_json(JsonValueScope &jv, const tonlib_api::raw_transactions &object); @@ -200,47 +268,49 @@ void to_json(JsonValueScope &jv, const tonlib_api::smc_MethodId &object); void to_json(JsonValueScope &jv, const tonlib_api::smc_methodIdNumber &object); void to_json(JsonValueScope &jv, const tonlib_api::smc_methodIdName &object); void to_json(JsonValueScope &jv, const tonlib_api::smc_runResult &object); -void to_json(JsonValueScope &jv, const tonlib_api::testGiver_accountState &object); -void to_json(JsonValueScope &jv, const tonlib_api::testWallet_accountState &object); -void to_json(JsonValueScope &jv, const tonlib_api::testWallet_initialAccountState &object); +void to_json(JsonValueScope &jv, const tonlib_api::ton_blockIdExt &object); void to_json(JsonValueScope &jv, const tonlib_api::tvm_cell &object); +void to_json(JsonValueScope &jv, const tonlib_api::tvm_list &object); void to_json(JsonValueScope &jv, const tonlib_api::tvm_numberDecimal &object); void to_json(JsonValueScope &jv, const tonlib_api::tvm_slice &object); void to_json(JsonValueScope &jv, const tonlib_api::tvm_StackEntry &object); void to_json(JsonValueScope &jv, const tonlib_api::tvm_stackEntrySlice &object); void to_json(JsonValueScope &jv, const tonlib_api::tvm_stackEntryCell &object); void to_json(JsonValueScope &jv, const tonlib_api::tvm_stackEntryNumber &object); +void to_json(JsonValueScope &jv, const tonlib_api::tvm_stackEntryTuple &object); +void to_json(JsonValueScope &jv, const tonlib_api::tvm_stackEntryList &object); void to_json(JsonValueScope &jv, const tonlib_api::tvm_stackEntryUnsupported &object); -void to_json(JsonValueScope &jv, const tonlib_api::uninited_accountState &object); -void to_json(JsonValueScope &jv, const tonlib_api::wallet_accountState &object); -void to_json(JsonValueScope &jv, const tonlib_api::wallet_initialAccountState &object); -void to_json(JsonValueScope &jv, const tonlib_api::wallet_v3_accountState &object); -void to_json(JsonValueScope &jv, const tonlib_api::wallet_v3_initialAccountState &object); +void to_json(JsonValueScope &jv, const tonlib_api::tvm_tuple &object); void to_json(JsonValueScope &jv, const tonlib_api::addLogMessage &object); void to_json(JsonValueScope &jv, const tonlib_api::changeLocalPassword &object); void to_json(JsonValueScope &jv, const tonlib_api::close &object); void to_json(JsonValueScope &jv, const tonlib_api::createNewKey &object); +void to_json(JsonValueScope &jv, const tonlib_api::createQuery &object); void to_json(JsonValueScope &jv, const tonlib_api::decrypt &object); void to_json(JsonValueScope &jv, const tonlib_api::deleteAllKeys &object); void to_json(JsonValueScope &jv, const tonlib_api::deleteKey &object); +void to_json(JsonValueScope &jv, const tonlib_api::dns_resolve &object); void to_json(JsonValueScope &jv, const tonlib_api::encrypt &object); void to_json(JsonValueScope &jv, const tonlib_api::exportEncryptedKey &object); void to_json(JsonValueScope &jv, const tonlib_api::exportKey &object); void to_json(JsonValueScope &jv, const tonlib_api::exportPemKey &object); -void to_json(JsonValueScope &jv, const tonlib_api::generic_createSendGramsQuery &object); -void to_json(JsonValueScope &jv, const tonlib_api::generic_getAccountState &object); -void to_json(JsonValueScope &jv, const tonlib_api::generic_sendGrams &object); +void to_json(JsonValueScope &jv, const tonlib_api::exportUnencryptedKey &object); +void to_json(JsonValueScope &jv, const tonlib_api::getAccountAddress &object); +void to_json(JsonValueScope &jv, const tonlib_api::getAccountState &object); void to_json(JsonValueScope &jv, const tonlib_api::getBip39Hints &object); void to_json(JsonValueScope &jv, const tonlib_api::getLogStream &object); void to_json(JsonValueScope &jv, const tonlib_api::getLogTagVerbosityLevel &object); void to_json(JsonValueScope &jv, const tonlib_api::getLogTags &object); void to_json(JsonValueScope &jv, const tonlib_api::getLogVerbosityLevel &object); +void to_json(JsonValueScope &jv, const tonlib_api::guessAccountRevision &object); void to_json(JsonValueScope &jv, const tonlib_api::importEncryptedKey &object); void to_json(JsonValueScope &jv, const tonlib_api::importKey &object); void to_json(JsonValueScope &jv, const tonlib_api::importPemKey &object); +void to_json(JsonValueScope &jv, const tonlib_api::importUnencryptedKey &object); void to_json(JsonValueScope &jv, const tonlib_api::init &object); void to_json(JsonValueScope &jv, const tonlib_api::kdf &object); void to_json(JsonValueScope &jv, const tonlib_api::liteServer_getInfo &object); +void to_json(JsonValueScope &jv, const tonlib_api::msg_decrypt &object); void to_json(JsonValueScope &jv, const tonlib_api::onLiteServerQueryError &object); void to_json(JsonValueScope &jv, const tonlib_api::onLiteServerQueryResult &object); void to_json(JsonValueScope &jv, const tonlib_api::options_setConfig &object); @@ -252,7 +322,6 @@ void to_json(JsonValueScope &jv, const tonlib_api::query_getInfo &object); void to_json(JsonValueScope &jv, const tonlib_api::query_send &object); void to_json(JsonValueScope &jv, const tonlib_api::raw_createAndSendMessage &object); void to_json(JsonValueScope &jv, const tonlib_api::raw_createQuery &object); -void to_json(JsonValueScope &jv, const tonlib_api::raw_getAccountAddress &object); void to_json(JsonValueScope &jv, const tonlib_api::raw_getAccountState &object); void to_json(JsonValueScope &jv, const tonlib_api::raw_getTransactions &object); void to_json(JsonValueScope &jv, const tonlib_api::raw_sendMessage &object); @@ -266,19 +335,8 @@ void to_json(JsonValueScope &jv, const tonlib_api::smc_getState &object); void to_json(JsonValueScope &jv, const tonlib_api::smc_load &object); void to_json(JsonValueScope &jv, const tonlib_api::smc_runGetMethod &object); void to_json(JsonValueScope &jv, const tonlib_api::sync &object); -void to_json(JsonValueScope &jv, const tonlib_api::testGiver_getAccountAddress &object); -void to_json(JsonValueScope &jv, const tonlib_api::testGiver_getAccountState &object); -void to_json(JsonValueScope &jv, const tonlib_api::testGiver_sendGrams &object); -void to_json(JsonValueScope &jv, const tonlib_api::testWallet_getAccountAddress &object); -void to_json(JsonValueScope &jv, const tonlib_api::testWallet_getAccountState &object); -void to_json(JsonValueScope &jv, const tonlib_api::testWallet_init &object); -void to_json(JsonValueScope &jv, const tonlib_api::testWallet_sendGrams &object); void to_json(JsonValueScope &jv, const tonlib_api::unpackAccountAddress &object); -void to_json(JsonValueScope &jv, const tonlib_api::wallet_getAccountAddress &object); -void to_json(JsonValueScope &jv, const tonlib_api::wallet_getAccountState &object); -void to_json(JsonValueScope &jv, const tonlib_api::wallet_init &object); -void to_json(JsonValueScope &jv, const tonlib_api::wallet_sendGrams &object); -void to_json(JsonValueScope &jv, const tonlib_api::wallet_v3_getAccountAddress &object); +void to_json(JsonValueScope &jv, const tonlib_api::withBlock &object); inline void to_json(JsonValueScope &jv, const ton::tonlib_api::Object &object) { ton::tonlib_api::downcast_call(const_cast(object),[&jv](const auto &object) { to_json(jv, object); }); } diff --git a/submodules/ton/tonlib-src/tl/generate/scheme/.tonlib_api.tl.swp b/submodules/ton/tonlib-src/tl/generate/scheme/.tonlib_api.tl.swp deleted file mode 100644 index 47e857185646f58a3f9afa7c0bd120f8db476c36..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16384 zcmeHO%a0p195zs1ZFvYzyd*<8aG=??X{(ZSOScb7fQ7QVZIP-na%P-lv=dLTJ-ZEv z#{r5E9C;jgTo9ZPh;oDf08Stz1Scerph#ReAh-aZXFSQwG+nl(MF=_Sw~6hae~-^U zd&Zt=d(+|8EZtGtOz^pu5bxB-#}0n>HaU3%AxtVRhV@ORX{FChDyKHiGJj7TFK#?2 z<60E^EUI*RDpxq=#{r+xv6#})RF?}bndVc<@9}6 zy0dY|RiwUUb2^_l+;%Iy{<=e}>+7T(1C9a5fMdWh;23ZWI0hU8j)DIL1A4HAJdH>$ zw$Zfg_eGWOKkesXTYq1r{SVu|)7HOUX}`pl*V^x|D($xDz8nLN0mp!2z%k$$a11yG z90QI4$ADwNG2j@u01U8z5VO~xF@NyN8fafkHIya22RUc*7ftH1%^Cmf2r0yKed!O!!+31AP9@|BJU-jN6nNY+<#TqTjFC~Gef zI*b~j(A(;?9S1|N$5gM;9%`=WG@UPZX%dpY1QGf*=KC@F&TG67aY%$B)I6ZJ(o?3k zk=W{zER^OdW(q2r6BRFTr4NKlTvjy0xvc)&RUctd#P#8NMe}l6U0bUEQ_Yk07Fj!M zCNh^RiVYQ6!?}Ar$CfKvC0kydIx>~L7K4m1IS{g_II7m;v_-SXE9ZyhdP2VfHLcUN zHdi)kl4fPY15(Y1QU9u_sXCgnY` z7VJDq7hhVA`n*RuF~rryH;QL+FokLOuLM-ER}QMsu-d>1T_y)-W_w}cDOxNvmbkBD zxw9g)iw-1T3gbkraxPC(qhVn@?^TmjbkgF)4wz>4+Fo#HrNx5hD~y7_tjoR5s3z7u zE(_&QczxAv82f#$6ohGmROYJ z-gTCPq9?tgU%uqH8wtEf+r_ean`14GZhDMcvsnb0ODkljc|X*4ERcJ?mt*5mIb}`F zq+FfsPe%3RL_Nc0V#HSIesCmQ$hlU43qv9X%wObz^>QW%Bp9U2v0U_f45^V_kZ?t4 z1UP7$h3M?qQ1@Z7o|IH_Y*F5-~{^ zarFUc`qr~IU`iQ7*0DUEad#tn`gIGgNQ_vS1Xu@U@xV+`Rr6!f3A-)PiD|$)4BHK_ zdOe<|x$xeRa5GmxGX;(8%eZY8AnxhmfHz=j-jo(lK(r5KHeuaL+rD<`Xd_mego5E7 z$5tnbdwBCZY9nuz*NLTvEHwF=Wn$PB#-7jcu6I^5P4}jL!VcUSInWZbydTRU94Y$M zED7xkWxC=ceez$qAJuLoUNkW+A|0fRC5XTZlif_^3zdxkIbbBPw0lBD;I@tqdayGj(d)zc!@fwZ;01&-Np?nYIvFNkro#Hp#;m;P)Lv;V&ld+SF5v;WVZ z&o5vf|10+D9|0$UFR?#=19%-+3%qRm95emg$1&g-a11yG90QI4$ADwNG2j?*3}AN= zJP>#7sSm{yr*^DDJ@g{J#M8%P*s*AS9Gl*J^KN!%Q&YPuqI4FgGX11KRzXu0RB#^P z2^sd86z68tZsn+sX`5p=-tF?>PP%F1=1p7bbhoiY7tEiyLs?N6lEx~I!+aU0`(BD; z5LFh!|5wI;OvZDF>;ZsLU!x1XP*MD20!lkkD2x-j7Y8-E7j^K$?1tfDo5M*?S%O9x zKAxVrRb|XseNV;$N0rggJQUPmZ-I3W=fpi=c%zzi$Am$m+??`PjAV}ML<&W5wj%Lt z@-z+&d5o$7_rp#IPbb7_OkT)XF*dAA5lYt_;G5qVL7Z?2oOX^$O}g16+SY0&&2t=#nd}^SWRv$lKs@;iPAN5P diff --git a/submodules/ton/tonlib-src/tl/generate/scheme/lite_api.tl b/submodules/ton/tonlib-src/tl/generate/scheme/lite_api.tl index 9604624a74..7d4495e72c 100644 --- a/submodules/ton/tonlib-src/tl/generate/scheme/lite_api.tl +++ b/submodules/ton/tonlib-src/tl/generate/scheme/lite_api.tl @@ -35,6 +35,7 @@ liteServer.blockState id:tonNode.blockIdExt root_hash:int256 file_hash:int256 da liteServer.blockHeader id:tonNode.blockIdExt mode:# header_proof:bytes = liteServer.BlockHeader; liteServer.sendMsgStatus status:int = liteServer.SendMsgStatus; liteServer.accountState id:tonNode.blockIdExt shardblk:tonNode.blockIdExt shard_proof:bytes proof:bytes state:bytes = liteServer.AccountState; +liteServer.runMethodResult mode:# id:tonNode.blockIdExt shardblk:tonNode.blockIdExt shard_proof:mode.0?bytes proof:mode.0?bytes state_proof:mode.1?bytes init_c7:mode.3?bytes lib_extras:mode.4?bytes exit_code:int result:mode.2?bytes = liteServer.RunMethodResult; liteServer.shardInfo id:tonNode.blockIdExt shardblk:tonNode.blockIdExt shard_proof:bytes shard_descr:bytes = liteServer.ShardInfo; liteServer.allShardsInfo id:tonNode.blockIdExt proof:bytes data:bytes = liteServer.AllShardsInfo; liteServer.transactionInfo id:tonNode.blockIdExt proof:bytes transaction:bytes = liteServer.TransactionInfo; @@ -48,6 +49,7 @@ liteServer.blockLinkBack to_key_block:Bool from:tonNode.blockIdExt to:tonNode.bl liteServer.blockLinkForward to_key_block:Bool from:tonNode.blockIdExt to:tonNode.blockIdExt dest_proof:bytes config_proof:bytes signatures:liteServer.SignatureSet = liteServer.BlockLink; liteServer.partialBlockProof complete:Bool from:tonNode.blockIdExt to:tonNode.blockIdExt steps:(vector liteServer.BlockLink) = liteServer.PartialBlockProof; liteServer.configInfo mode:# id:tonNode.blockIdExt state_proof:bytes config_proof:bytes = liteServer.ConfigInfo; +liteServer.validatorStats mode:# id:tonNode.blockIdExt count:int complete:Bool state_proof:bytes data_proof:bytes = liteServer.ValidatorStats; liteServer.debug.verbosity value:int = liteServer.debug.Verbosity; @@ -62,6 +64,7 @@ liteServer.getState id:tonNode.blockIdExt = liteServer.BlockState; liteServer.getBlockHeader id:tonNode.blockIdExt mode:# = liteServer.BlockHeader; liteServer.sendMessage body:bytes = liteServer.SendMsgStatus; liteServer.getAccountState id:tonNode.blockIdExt account:liteServer.accountId = liteServer.AccountState; +liteServer.runSmcMethod mode:# id:tonNode.blockIdExt account:liteServer.accountId method_id:long params:bytes = liteServer.RunMethodResult; liteServer.getShardInfo id:tonNode.blockIdExt workchain:int shard:long exact:Bool = liteServer.ShardInfo; liteServer.getAllShardsInfo id:tonNode.blockIdExt = liteServer.AllShardsInfo; liteServer.getOneTransaction id:tonNode.blockIdExt account:liteServer.accountId lt:long = liteServer.TransactionInfo; @@ -71,6 +74,7 @@ liteServer.listBlockTransactions id:tonNode.blockIdExt mode:# count:# after:mode liteServer.getBlockProof mode:# known_block:tonNode.blockIdExt target_block:mode.0?tonNode.blockIdExt = liteServer.PartialBlockProof; liteServer.getConfigAll mode:# id:tonNode.blockIdExt = liteServer.ConfigInfo; liteServer.getConfigParams mode:# id:tonNode.blockIdExt param_list:(vector int) = liteServer.ConfigInfo; +liteServer.getValidatorStats#091a58bc mode:# id:tonNode.blockIdExt limit:int start_after:mode.0?int256 modified_after:mode.2?int = liteServer.ValidatorStats; liteServer.queryPrefix = Object; liteServer.query data:bytes = Object; diff --git a/submodules/ton/tonlib-src/tl/generate/scheme/lite_api.tlo b/submodules/ton/tonlib-src/tl/generate/scheme/lite_api.tlo index 9b01c0d881f3ff2d6c37ae801295789e59e6ed3f..d524f54b71f56584a42886ea5715b9f4c04b8dfc 100644 GIT binary patch delta 626 zcmcZ*){w~iXtur;0~F|N@WOHAG%#4=fe*MOA?N`NSuG5N4U2z{`Oq5+K0C304DC#yB}p zP+X8bGcU6wKG_^5$_x~h5Xs3*ichU5DM~D6fJv}`lyh^YR)Cb}r=&7Wt{0OOWGe!D z60VAA@bp)kODq8H&Fd7(ntMudusekre&t4KqQcS8ptUPcF5)i^%qR4mtv2_ zh$A@x7-_+|$&i!)i!g-M3aTocoVnm+5}!G_QBInjtst=|F}HZ~eHmGB_)U({`T_uM CTgr3* delta 64 zcmZojyb#9wXtur;0~Ba& = multisig.Order; +// multisig.orders = orders:vector = multisig.Orders; +// +// multisig.initialAccountState public_keys:vector wallet_id:int64 k:int32 = InitialAccountState; +// multisig.accountState public_keys:vector wallet_id:int64 k:int32 = AccountState; +// +// multisig.sign private_key:InputKey order:multisig.unsignedOrder = multisig.Signature; +// multisig.getPendingOrders account_address:accountAddress unsigned_by:int32 = multisig.Orders; + diff --git a/submodules/ton/tonlib-src/tl/generate/scheme/ton_api.tl b/submodules/ton/tonlib-src/tl/generate/scheme/ton_api.tl index 7617f1fe09..1f819d5dd3 100644 --- a/submodules/ton/tonlib-src/tl/generate/scheme/ton_api.tl +++ b/submodules/ton/tonlib-src/tl/generate/scheme/ton_api.tl @@ -362,6 +362,9 @@ tonNode.capabilities version:int capabilities:long = tonNode.Capabilities; tonNode.success = tonNode.Success; +tonNode.archiveNotFound = tonNode.ArchiveInfo; +tonNode.archiveInfo id:long = tonNode.ArchiveInfo; + ---functions--- tonNode.getNextBlockDescription prev_block:tonNode.blockIdExt = tonNode.BlockDescription; @@ -385,6 +388,8 @@ tonNode.downloadBlockProof block:tonNode.blockIdExt = tonNode.Data; tonNode.downloadBlockProofs blocks:(vector tonNode.blockIdExt) = tonNode.DataList; tonNode.downloadBlockProofLink block:tonNode.blockIdExt = tonNode.Data; tonNode.downloadBlockProofLinks blocks:(vector tonNode.blockIdExt) = tonNode.DataList; +tonNode.getArchiveInfo masterchain_seqno:int = tonNode.ArchiveInfo; +tonNode.getArchiveSlice archive_id:long offset:long max_size:int = tonNode.Data; tonNode.getCapabilities = tonNode.Capabilities; @@ -417,7 +422,8 @@ db.block.info#4ac6e727 id:tonNode.blockIdExt flags:# prev_left:flags.1?tonNode.b next_right:flags.4?tonNode.blockIdExt lt:flags.13?long ts:flags.14?int - state:flags.17?int256 = db.block.Info; + state:flags.17?int256 + masterchain_ref_seqno:flags.23?int = db.block.Info; db.block.packedInfo id:tonNode.blockIdExt unixtime:int offset:long = db.block.Info; db.block.archivedInfo id:tonNode.blockIdExt flags:# next:flags.0?tonNode.blockIdExt = db.block.Info; @@ -437,6 +443,7 @@ db.filedb.key.proof block_id:tonNode.blockIdExt = db.filedb.Key; db.filedb.key.proofLink block_id:tonNode.blockIdExt = db.filedb.Key; db.filedb.key.signatures block_id:tonNode.blockIdExt = db.filedb.Key; db.filedb.key.candidate id:db.candidate.id = db.filedb.Key; +db.filedb.key.blockInfo block_id:tonNode.blockIdExt = db.filedb.Key; db.filedb.value key:db.filedb.Key prev:int256 next:int256 file_hash:int256 = db.filedb.Value; @@ -446,6 +453,7 @@ db.state.gcBlockId block:tonNode.blockIdExt = db.state.GcBlockId; db.state.shardClient block:tonNode.blockIdExt = db.state.ShardClient; db.state.asyncSerializer block:tonNode.blockIdExt last:tonNode.blockIdExt last_ts:int = db.state.AsyncSerializer; db.state.hardforks blocks:(vector tonNode.blockIdExt) = db.state.Hardforks; +db.state.dbVersion version:int = db.state.DbVersion; db.state.key.destroyedSessions = db.state.Key; db.state.key.initBlockId = db.state.Key; @@ -453,6 +461,7 @@ db.state.key.gcBlockId = db.state.Key; db.state.key.shardClient = db.state.Key; db.state.key.asyncSerializer = db.state.Key; db.state.key.hardforks = db.state.Key; +db.state.key.dbVersion = db.state.Key; db.lt.el.key workchain:int shard:long idx:int = db.lt.Key; db.lt.desc.key workchain:int shard:long = db.lt.Key; @@ -463,6 +472,14 @@ db.lt.desc.value first_idx:int last_idx:int last_seqno:int last_lt:long last_ts: db.lt.shard.value workchain:int shard:long = db.lt.shard.Value; db.lt.status.value total_shards:int = db.lt.status.Value; +db.files.index.key = db.files.Key; +db.files.package.key package_id:int key:Bool temp:Bool = db.files.Key; + +db.files.index.value packages:(vector int) key_packages:(vector int) temp_packages:(vector int) = db.files.index.Value; +db.files.package.firstBlock workchain:int shard:long seqno:int unixtime:int lt:long = db.files.package.FirstBlock; +db.files.package.value package_id:int key:Bool temp:Bool firstblocks:(vector db.files.package.firstBlock) deleted:Bool + = db.files.package.Value; + ---functions--- ---types--- @@ -597,3 +614,25 @@ engine.validator.createElectionBid election_date:int election_addr:string wallet engine.validator.checkDhtServers id:int256 = engine.validator.DhtServersStatus; engine.validator.controlQuery data:bytes = Object; + + +---types--- + +http.header name:string value:string = http.Header; +http.payloadPart data:bytes trailer:(vector http.header) last:Bool = http.PayloadPart; +http.response http_version:string status_code:int reason:string headers:(vector http.header) = http.Response; + +---functions--- + +http.request id:int256 method:string url:string http_version:string headers:(vector http.header) = http.Response; +http.getNextPayloadPart id:int256 seqno:int max_chunk_size:int = http.PayloadPart; + +---types--- + + +http.server.dnsEntry domain:string addr:adnl.id.short = http.server.DnsEntry; +http.server.host domains:(vector string) ip:int port:int adnl_id:adnl.id.short = http.server.Host; + +http.server.config dhs:(vector http.server.dnsEntry) local_hosts:(vector http.server.host) = http.server.Config; + +---functions--- diff --git a/submodules/ton/tonlib-src/tl/generate/scheme/ton_api.tlo b/submodules/ton/tonlib-src/tl/generate/scheme/ton_api.tlo index 28e5cfa571a8a4186268ed8c4c1f564769dc4492..5507d156b03e7a5d235a813ccb89d400f963730a 100644 GIT binary patch delta 2509 zcmaJ?Uu+X~9KX_AyLGLUd0SiCxlRgfGL9LE%sI@a$R8<#!8So5-O>APZPwkDyDMx8 zib{N1gz?2C1Rm5#Fvf??iwO@XG#L;R{PO^D5E7Aq#wU0%kp~jJ@BL|yW3vz2-S_|R zbD!Vmd;BZ+olEY(?UO6pDf4%BI#~xpypj{s z!xK~C+U3`hcj}xm;PN%7r>eeih5m`JzFwobWrb4+yLL}Mk>so>zl0I6wbB1`WpL5mlOI=S6eZ7YARJF5?8g84W^+)tZRN&tBFAs#Bn4-!k0pN@ueB$VOpMRO68ukLwxrZo~c-mk)}Y z7ORJnoi3Pqfo`lF;betqv0PS2Nn|i3lf8mSQ47q^7lLAQ6#QF)>g?uQbQr(m^-DEL z^h&RKS}NCkR74y6vaN~MA6olX84s(rw>T`Pwy&zP3M_!ndX@v-YX*1pCY-^&j)KSf zob@t&W=MP}3}5##3>G)%rmj8h+x773i5a-Hjj2Qw9-VHcucJZ_hhk3>0-r2{(f;6j z3o2#~A}5fhGHZ}-SmP=()Ol>Q*_*xWrcaj%Yf%!jsZzdMdyf9`TeHt}r?R|W0%5#y zaw{xP1mH`~4{b|>URog|d5VISll5zzz2>?c`|xsT)zF8tTD>aGUT}1G9P(#_e!n(T z%3%xyuv^Lc{__nmb(VP%Yv}`Oe-O~Quiaqj+MyqNS3q&+`eR2D5bI7r@6IsXZ>(I8 zPJ6LA?<1ATfSEx`d8G$bMxNEJFruwrR6P_0j~2QR-&fvY_l#(pldA=dEnBu5m& zL+fOW#s=zv{+piIqdLG_IzXWvZobt@N?n zj)vgVv8LzHYwueY#C%y0wE(nZ6*q7v79UH}RbEBnwEHIMUya5x@L*RA+9sJUjJ4M+ zOQ~c^DMg_T>(S;^ew5FYCaAia8`IJLYCL{HPNg+%g!`QluS7Um6et)U3s-pYe6aWR zh92y0amLa&Y+xV4Dco#Y6b7?H6x!|ZxcQ91#ClY9t11Flt+ABLr81g&8xcED*{ukx zFV?g7eQY=I=5Ek}&}Z-M;l&Y6(e>kbX^!V5RFa|kE)296eQc%RP+9=m?WlTZzQNG=qWa&vHC{NzVL|=ZZwt76olcFoPC?X`R4i+PNMxjG0o{jVkNS-Ky*kfqE&#aknoNW zB_r}Wz_hy{<&a2$Ik{J+S9m^peRDbHUD9=Z#XEHtY}y%Y8=SIWbHT(F28u@(Z*+o| z>3Jz$0==BQJ(o?B!wFwMf^Mw@p9!kIet_E?f~%{8kpD3O=b9L3{UNBvetO{f52u-A A6#xJL delta 514 zcmaEIjCsl`X5L4$^{p77V9iEeb57CQdu$kaQh|nx1P@TUxFoS86{3iN4XA3f3GWV$%`D;`ESqbj*RU}PZPrvO*J0$` zywES1ak7IU$K(eA0-Hku9%q-o%mT!ByLn=}L5I!)4X8@qW+`W~6hF&!5~ cHy@ezLYC2U^V&V!Vw*j#2(WL?x$}b!00T6=bpQYW diff --git a/submodules/ton/tonlib-src/tl/generate/scheme/tonlib_api.tl b/submodules/ton/tonlib-src/tl/generate/scheme/tonlib_api.tl index e6778df578..beb5d64a0c 100644 --- a/submodules/ton/tonlib-src/tl/generate/scheme/tonlib_api.tl +++ b/submodules/ton/tonlib-src/tl/generate/scheme/tonlib_api.tl @@ -8,6 +8,9 @@ bytes = Bytes; secureString = SecureString; secureBytes = SecureBytes; +object ? = Object; +function ? = Function; + boolFalse = Bool; boolTrue = Bool; @@ -22,7 +25,8 @@ keyStoreTypeInMemory = KeyStoreType; config config:string blockchain_name:string use_callbacks_for_network:Bool ignore_cache:Bool = Config; options config:config keystore_type:KeyStoreType = Options; -options.configInfo default_wallet_id:int53 = options.ConfigInfo; +options.configInfo default_wallet_id:int64 = options.ConfigInfo; +options.info config_info:options.configInfo = options.Info; key public_key:string secret:secureBytes = Key; inputKeyRegular key:key local_password:secureBytes = InputKey; @@ -30,61 +34,108 @@ inputKeyFake = InputKey; exportedKey word_list:vector = ExportedKey; exportedPemKey pem:secureString = ExportedPemKey; exportedEncryptedKey data:secureBytes = ExportedEncryptedKey; +exportedUnencryptedKey data:secureBytes = ExportedUnencryptedKey; bip39Hints words:vector = Bip39Hints; +adnlAddress adnl_address:string = AdnlAddress; + accountAddress account_address:string = AccountAddress; +accountRevisionList revisions:vector = AccountRevisionList; unpackedAccountAddress workchain_id:int32 bounceable:Bool testnet:Bool addr:bytes = UnpackedAccountAddress; internal.transactionId lt:int64 hash:bytes = internal.TransactionId; -raw.initialAccountState code:bytes data:bytes = raw.InitialAccountState; -raw.accountState balance:int64 code:bytes data:bytes last_transaction_id:internal.transactionId frozen_hash:bytes sync_utime:int53 = raw.AccountState; -raw.message source:string destination:string value:int64 fwd_fee:int64 ihr_fee:int64 created_lt:int64 body_hash:bytes message:bytes = raw.Message; +ton.blockId workchain:int32 shard:int64 seqno:int32 = internal.BlockId; +ton.blockIdExt workchain:int32 shard:int64 seqno:int32 root_hash:bytes file_hash:bytes = ton.BlockIdExt; + +raw.fullAccountState balance:int64 code:bytes data:bytes last_transaction_id:internal.transactionId block_id:ton.blockIdExt frozen_hash:bytes sync_utime:int53 = raw.FullAccountState; +raw.message source:string destination:string value:int64 fwd_fee:int64 ihr_fee:int64 created_lt:int64 body_hash:bytes msg_data:msg.Data = raw.Message; raw.transaction utime:int53 data:bytes transaction_id:internal.transactionId fee:int64 storage_fee:int64 other_fee:int64 in_msg:raw.message out_msgs:vector = raw.Transaction; raw.transactions transactions:vector previous_transaction_id:internal.transactionId = raw.Transactions; -testWallet.initialAccountState public_key:string = testWallet.InitialAccountState; -testWallet.accountState balance:int64 seqno:int32 last_transaction_id:internal.transactionId sync_utime:int53 = testWallet.AccountState; +raw.initialAccountState code:bytes data:bytes = InitialAccountState; +testGiver.initialAccountState = InitialAccountState; +testWallet.initialAccountState public_key:string = InitialAccountState; +wallet.initialAccountState public_key:string = InitialAccountState; +wallet.v3.initialAccountState public_key:string wallet_id:int64 = InitialAccountState; +wallet.highload.v1.initialAccountState public_key:string wallet_id:int64 = InitialAccountState; +wallet.highload.v2.initialAccountState public_key:string wallet_id:int64 = InitialAccountState; +dns.initialAccountState public_key:string wallet_id:int64 = InitialAccountState; -wallet.initialAccountState public_key:string = wallet.InitialAccountState; -wallet.accountState balance:int64 seqno:int32 last_transaction_id:internal.transactionId sync_utime:int53 = wallet.AccountState; +raw.accountState code:bytes data:bytes frozen_hash:bytes = AccountState; +testWallet.accountState seqno:int32 = AccountState; +wallet.accountState seqno:int32 = AccountState; +wallet.v3.accountState wallet_id:int64 seqno:int32 = AccountState; +wallet.highload.v1.accountState wallet_id:int64 seqno:int32 = AccountState; +wallet.highload.v2.accountState wallet_id:int64 = AccountState; +testGiver.accountState seqno:int32 = AccountState; +dns.accountState wallet_id:int64 = AccountState; +uninited.accountState frozen_hash:bytes = AccountState; -wallet.v3.initialAccountState public_key:string wallet_id:int53 = wallet.v3.InitialAccountState; -wallet.v3.accountState balance:int64 wallet_id:int53 seqno:int32 last_transaction_id:internal.transactionId sync_utime:int53 = wallet.v3.AccountState; - -testGiver.accountState balance:int64 seqno:int32 last_transaction_id:internal.transactionId sync_utime:int53= testGiver.AccountState; - -uninited.accountState balance:int64 last_transaction_id:internal.transactionId frozen_hash:bytes sync_utime:int53 = uninited.AccountState; - -//generic.initialAccountStateRaw initital_account_state:raw.initialAccountState = generic.InitialAccountState; -//generic.initialAccountStateTestWallet initital_account_state:testWallet.initialAccountState = generic.InitialAccountState; -//generic.initialAccountStateWallet initital_account_state:wallet.initialAccountState = generic.InitialAccountState; - -generic.accountStateRaw account_state:raw.accountState = generic.AccountState; -generic.accountStateTestWallet account_state:testWallet.accountState = generic.AccountState; -generic.accountStateWallet account_state:wallet.accountState = generic.AccountState; -generic.accountStateWalletV3 account_state:wallet.v3.accountState = generic.AccountState; -generic.accountStateTestGiver account_state:testGiver.accountState = generic.AccountState; -generic.accountStateUninited account_state:uninited.accountState = generic.AccountState; - -sendGramsResult sent_until:int53 body_hash:bytes = SendGramsResult; +fullAccountState balance:int64 last_transaction_id:internal.transactionId block_id:ton.blockIdExt sync_utime:int53 account_state:AccountState = FullAccountState; syncStateDone = SyncState; syncStateInProgress from_seqno:int32 to_seqno:int32 current_seqno:int32 = SyncState; -fees in_fwd_fee:int53 storage_fee:int53 gas_fee:int53 fwd_fee:int53= Fees; -query.fees source_fees:fees destination_fees:fees = query.Fees; +// +// MSG +// + +msg.dataRaw body:bytes = msg.Data; +msg.dataText text:bytes = msg.Data; +msg.dataDecryptedText text:bytes = msg.Data; +msg.dataEncryptedText text:bytes = msg.Data; + +msg.dataArray elements:vector = msg.DataArray; + +msg.message destination:accountAddress amount:int64 data:msg.Data = msg.Message; + +// +// DNS +// + +dns.entryDataUnknown bytes:bytes = dns.EntryData; +dns.entryDataText text:string = dns.EntryData; +dns.entryDataNextResolver resolver:AccountAddress = dns.EntryData; +dns.entryDataSmcAddress smc_address:AccountAddress = dns.EntryData; +dns.entryDataAdnlAddress adnl_address:AdnlAddress = dns.EntryData; + +dns.entry name:string category:int32 entry:dns.EntryData = dns.Entry; + +dns.actionDeleteAll = dns.Action; +// use category = 0 to delete all entries +dns.actionDelete name:string category:int32 = dns.Action; +dns.actionSet entry:dns.entry = dns.Action; + +dns.resolved entries:vector = dns.Resolved; + +// +// Actions +// + +actionNoop = Action; +actionMsg messages:vector allow_send_to_uninited:Bool = Action; +actionDns actions:vector = Action; +//actionMultisig actions:vector = Action; + +fees in_fwd_fee:int53 storage_fee:int53 gas_fee:int53 fwd_fee:int53 = Fees; +query.fees source_fees:fees destination_fees:vector = query.Fees; +// query.emulationResult exit_code:int32 fees:fees = query.EmulationResult; query.info id:int53 valid_until:int53 body_hash:bytes = query.Info; -tvm.slice bytes:string = tvm.Slice; -tvm.cell bytes:string = tvm.Cell; +tvm.slice bytes:bytes = tvm.Slice; +tvm.cell bytes:bytes = tvm.Cell; tvm.numberDecimal number:string = tvm.Number; +tvm.tuple elements:vector = tvm.Tuple; +tvm.list elements:vector = tvm.List; tvm.stackEntrySlice slice:tvm.slice = tvm.StackEntry; tvm.stackEntryCell cell:tvm.cell = tvm.StackEntry; tvm.stackEntryNumber number:tvm.Number = tvm.StackEntry; +tvm.stackEntryTuple tuple:tvm.Tuple = tvm.StackEntry; +tvm.stackEntryList list:tvm.List = tvm.StackEntry; tvm.stackEntryUnsupported = tvm.StackEntry; smc.info id:int53 = smc.Info; @@ -121,10 +172,10 @@ liteServer.info now:int53 version:int32 capabilities:int64 = liteServer.Info; ---functions--- -init options:options = Ok; +init options:options = options.Info; close = Ok; -options.setConfig config:config = Ok; +options.setConfig config:config = options.ConfigInfo; options.validateConfig config:config = options.ConfigInfo; createNewKey local_password:secureBytes mnemonic_password:secureBytes random_extra_seed:secureBytes = Key; @@ -133,9 +184,11 @@ deleteAllKeys = Ok; exportKey input_key:InputKey = ExportedKey; exportPemKey input_key:InputKey key_password:secureBytes = ExportedPemKey; exportEncryptedKey input_key:InputKey key_password:secureBytes = ExportedEncryptedKey; +exportUnencryptedKey input_key:InputKey = ExportedUnencryptedKey; importKey local_password:secureBytes mnemonic_password:secureBytes exported_key:exportedKey = Key; importPemKey local_password:secureBytes key_password:secureBytes exported_key:exportedPemKey = Key; importEncryptedKey local_password:secureBytes key_password:secureBytes exported_encrypted_key:exportedEncryptedKey = Key; +importUnencryptedKey local_password:secureBytes exported_unencrypted_key:exportedUnencryptedKey = Key; changeLocalPassword input_key:InputKey new_local_password:secureBytes = Key; encrypt decrypted_data:secureBytes secret:secureBytes = Data; @@ -147,51 +200,44 @@ packAccountAddress account_address:unpackedAccountAddress = AccountAddress; getBip39Hints prefix:string = Bip39Hints; //raw.init initial_account_state:raw.initialAccountState = Ok; -raw.getAccountAddress initital_account_state:raw.initialAccountState = AccountAddress; -raw.getAccountState account_address:accountAddress = raw.AccountState; -raw.getTransactions account_address:accountAddress from_transaction_id:internal.transactionId = raw.Transactions; +raw.getAccountState account_address:accountAddress = raw.FullAccountState; +raw.getTransactions private_key:InputKey account_address:accountAddress from_transaction_id:internal.transactionId = raw.Transactions; raw.sendMessage body:bytes = Ok; raw.createAndSendMessage destination:accountAddress initial_account_state:bytes data:bytes = Ok; raw.createQuery destination:accountAddress init_code:bytes init_data:bytes body:bytes = query.Info; -testWallet.init private_key:InputKey = Ok; -testWallet.getAccountAddress initital_account_state:testWallet.initialAccountState = AccountAddress; -testWallet.getAccountState account_address:accountAddress = testWallet.AccountState; -testWallet.sendGrams private_key:InputKey destination:accountAddress seqno:int32 amount:int64 message:bytes = SendGramsResult; +sync = ton.BlockIdExt; -wallet.init private_key:InputKey = Ok; -wallet.getAccountAddress initital_account_state:wallet.initialAccountState = AccountAddress; -wallet.getAccountState account_address:accountAddress = wallet.AccountState; -wallet.sendGrams private_key:InputKey destination:accountAddress seqno:int32 valid_until:int53 amount:int64 message:bytes = SendGramsResult; +// revision = 0 -- use default revision +// revision = x (x > 0) -- use revision x +// revision = -1 -- use experimental (newest) revision. Only for debug purpose +getAccountAddress initial_account_state:InitialAccountState revision:int32 = AccountAddress; +guessAccountRevision initial_account_state:InitialAccountState = AccountRevisionList; +getAccountState account_address:accountAddress = FullAccountState; +createQuery private_key:InputKey address:accountAddress timeout:int32 action:Action = query.Info; -wallet.v3.getAccountAddress initital_account_state:wallet.v3.initialAccountState = AccountAddress; - -testGiver.getAccountState = testGiver.AccountState; -testGiver.getAccountAddress = AccountAddress; -testGiver.sendGrams destination:accountAddress seqno:int32 amount:int64 message:bytes = SendGramsResult; - -sync = Ok; - -//generic.getAccountAddress initital_account_state:generic.InitialAccountState = AccountAddress; -generic.getAccountState account_address:accountAddress = generic.AccountState; -generic.sendGrams private_key:InputKey source:accountAddress destination:accountAddress amount:int64 timeout:int32 allow_send_to_uninited:Bool message:bytes = SendGramsResult; - -generic.createSendGramsQuery private_key:InputKey source:accountAddress destination:accountAddress amount:int64 timeout:int32 allow_send_to_uninited:Bool message:bytes = query.Info; +msg.decrypt input_key:InputKey data:msg.dataArray = msg.DataArray; query.send id:int53 = Ok; query.forget id:int53 = Ok; query.estimateFees id:int53 ignore_chksig:Bool = query.Fees; +// query.emulate id:int53 ignore_chksig:Bool = query.EmulationResult; query.getInfo id:int53 = query.Info; smc.load account_address:accountAddress = smc.Info; +//smc.forget id:int53 = Ok; smc.getCode id:int53 = tvm.Cell; smc.getData id:int53 = tvm.Cell; smc.getState id:int53 = tvm.Cell; smc.runGetMethod id:int53 method:smc.MethodId stack:vector = smc.RunResult; +dns.resolve account_address:accountAddress name:string category:int32 ttl:int32 = dns.Resolved; + onLiteServerQueryResult id:int64 bytes:bytes = Ok; onLiteServerQueryError id:int64 error:error = Ok; +withBlock id:ton.blockIdExt function:Function = Object; + runTests dir:string = Ok; liteServer.getInfo = liteServer.Info; diff --git a/submodules/ton/tonlib-src/tl/generate/scheme/tonlib_api.tlo b/submodules/ton/tonlib-src/tl/generate/scheme/tonlib_api.tlo index a670da5a67ca0761aba73e8ccd111a1ce2649bc0..6a730d89e12188541e71d228f12c42ccf3111558 100644 GIT binary patch delta 5432 zcmb7Ie^3p8{Wo?7xl|;g51}~SJ`S&|>(^EY@i4Zd>IAgW^xQ5H{_(MUD z-yad9QNlmgxtq1$e&Ly_hgx^^ha-~c-xLxcJ{ANx%QiJwlyS0h8eiR=GjcopWKoepKI|-UWPFuc-BGVp{Fdk zvR;gagM&nQqLA(9Bb&#qfsiCdLf)WjaWL%bT~1e^&DfbW>HpCyroL#mO9o;%M9O*0 zux&-AI_rrH$uA#o=P4q3CfB!exZ7lJpf?I#7G)EN2gYD^a;A%EcIaN2k zR+Qe}aB$^KEACN2Q@s&A6p>P3%#sVEg>INE6ri6s@wlQz*z^Z@7WS0d%_<8E|1K$k zo7tusJ?Z8v7jNebd4oYwnjtTNGeO9T6FYwf?)lR~46uEE0bCcX&|K+2VNH5rlYe`n zbB-dcC(zv!414{q!J4FkzaDMPlixj%h*p~vja78Bz@CCcdz~5{dJoQ(OmF4E_S$y+ zi!LjM#{&*$hM;fg4PZKSev54&6d;i;`gIV~7Qa?lj>j6*bH8{xwj|w4v&8CfxSzqq zgbsm6A6b&>G&Ozy4V=@u!rGx%XPIT5RncxH&SM}%=#Hj7B?#AM3mir!+^wyLry5N4 zdZc1^`7#BmB@~@TQXM-@mJ$VFv11)(B2|qCsYbJ?cRGvWSQ{x8T|iLE2x zS5!xXVk&{rN+$?*$7bz`sM|sWb*mV@G@ExR*_W$S`S(W>T4>;S4XBs^^C8YriUDGm9w*w{j(ZyyjN!>%q-j51`* zc7ot&gZ6CRe(u&MK0N|$I=<&PUKVdUlGG2lhU%rky7{DPD-1rkh?pqcT#Dpct*~Rs zz*=9iH;&=$qI*tkr#kRt6>8jOGTS3VY-)~$rOglA7wYIotgg7xz+oE$Qb~&|-VZ6U zNBSWK=TLJak$?gHRq-dJn7z~mH zGKOkPAtv&AT+`CVyRabX!pH)SwPzi7Uu$u3F4>F9t9mcegJoV1kBuAc%A&!5k96*| zkyEY@xvM)jue2V`p@lap)Ci0AMJ~M)P!rnAOJ!R&mpkmZiKJ9gd4)`Mq})A%e5$&b z{U&{fKg+?sF&ghEX$P60lSKPU%8EK+zp3J=+ty?MU_r}x_Dt+1>}wf4IH%Yd0TCSS zmkb=PmOI;2W+Zr!Fr^hm2RigvO-6d=q z?DCM_d~2xgz6{aEL|9r1dp$gdgV@H0 zgKXJLll4#V-2bz0?l4H9QE~W*u<~)>r4YzsX^HOBOH#!_*^gj(!M_PV$v0 zy-Vb4TfRc^_JOrdH#7=XI}Y@5g>$jHk8-Tz(w)I@mU^c|MQI7WRv7tCu`YDW4@fNw zE98&(%<+Z0<<}#3!$$fM+ubl~aMYf>aV7`zuFmS1pFy!YuTR#6$G+19H=7(Rd4X|P z!46L;dR5H%*y9HIWyw0%DSw=3cIamAH4D0#HqTupsVo*s_fNX^a?#@7&4nvZ&#rUgYLJSJ`HsUl-%gX{SFFCdh| Ag8%>k delta 3414 zcmbVOZ%k8H6o0Qgu%$o?6e#Tj>r%0VQb0fua08J+Cr%JI_kjpqc|u(+*gkYFe$d1? zOk@U*W*Rk{!I&+&#iY8iY;KSlqnTO!z#J|n;1UZfw}rLz01cNl_HbWZI}NkUQPZb`+p`UAT%fBl z=-C$9z=it#{Lri!2IBAK{Pb|5#MI3NxS-GLs`Gk#`vZI%@8LNDnE-p^vY>fUCv%3n zr30tdJoM1S6kV(;fB|i@?v*!|LjNX@-_P;U0iCot_0r(c&vF$3 zZWywp1Mx5yj$ghGHHmf@NOYw94J*fV{Els|Howoy!DiZ$;ePwU8!3W`_juoG2=KvO z6oVVJT%@Y6W%LJpBzLYWdPy?T{Nry!gXueC=aYQp&$HiHBxfWS>(<6Q{h5+=M`<)9 z*{0FZaMzeK?-wU_&>6HF^7Y-}!>QA8Fp)7DK58{F;mO5Dx>zV>D7utryLBb4Swl)@ z{bedYk@)!zQb(Vk0$ZjTP88dqGhfSKVEDFecid7qvf+~~x#}K8)i-!{A|nuvhPtf9 ztypAQqF1m!!Kq!fe;gwu6ZJ!GV*8izcgJ&Mp>2#*kcvWGhxJ_ub?}_4(h>`GlTd?b z#8#}%LWm^~s(xpmjre*g*;G`XtysW?Q1|nv>T_bD;_d~0t5K2t3!z?p_2#vhxxOY5 zRGq6C=^G0*JnOL2EOu~OZy)dL4TN0Y-oO@Lw>z+t{GmI5VIxtyydPzhFltdyhXh$L?z$q7iKZ%gAoPpg%j&k%U*NNx` z_MS>N&?m4P#$EMDV>?=uvvY~6=uvgHaiNf>o5O#&S~RC!BpIN^#WH9O-z!d{g%Lb0 zDHBa)%WE_YiUROuYZxpIOsAN2IKX8YlKe8TmD@mDgDCKa^ z%re4&RH7UQ$_SOLE0>|rhwH=(yfLSkz>#T$niLk8qGIGvE=DNPqAvkBWXXu9&;~}! z8tlqs{E;WT6h5%>2|ZF%Lx<;9-KGmQfAu6qWWpQd$i*GG=v%RI$wd9f=Qm?Yi{NB+ z0ZbGbVY1o?+O>8lbJ}30+6D)W&Lpg?qG6mi&D_n&$Q{wm@pX!80#y>GYb#6CSHTK{ zW-3({!^k~FQSu%2pK@Tu8;h;;lijXnHClc6*LNAB5isjE!Sx3FaFucRl!Wtm%VQ(2l@X2mY6ZMEsYJ8<#?CbTQy zr6`zMywuV8`S(*+d^3rUuKDEZy1IfyI?rCx6(UdITrJCuv_CRr#|oAnhq68*G36Fk zE90>fhmNGrV?^j6lYs$xZGq4m#ZG&aTK8ax%z0D;`b^#ki%{a_uQ*vLc@iw=|Gf1Q zl$O-XUbFXUo+T!@xLMR{WP71nv=1ilJ8Mu(6bM2Hho?xBZX*{*t(Guv>6;gpzhF`X zMvj7{EuTib(4N?qs21uI5n2KEwelMu9?QFImL84&s^R}Q20`Y?G1yic-m}WD)p=m? z2v8*P2=dixSxs%7(M#DpYx_$cT^LO@N. - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "tl_writer_java.h" @@ -34,7 +34,8 @@ int TD_TL_writer_java::get_max_arity() const { bool TD_TL_writer_java::is_built_in_simple_type(const std::string &name) const { return name == "Bool" || name == "Int32" || name == "Int53" || name == "Int64" || name == "Double" || - name == "String" || name == "Bytes" || name == "SecureString" || name == "SecureBytes"; + name == "String" || name == "Bytes" || name == "SecureString" || name == "SecureBytes" || name == "Object" || + name == "Function"; } bool TD_TL_writer_java::is_built_in_complex_type(const std::string &name) const { @@ -168,6 +169,12 @@ std::string TD_TL_writer_java::gen_type_name(const tl::tl_tree_type *tree_type) if (name == "Bytes" || name == "SecureBytes") { return "byte[]"; } + if (name == "Object") { + return gen_base_type_class_name(0); + } + if (name == "Function") { + return gen_base_function_class_name(); + } if (name == "Vector") { assert(t->arity == 1); diff --git a/submodules/ton/tonlib-src/tl/generate/tl_writer_jni_cpp.cpp b/submodules/ton/tonlib-src/tl/generate/tl_writer_jni_cpp.cpp index 328ea0b463..3eacfe77f4 100644 --- a/submodules/ton/tonlib-src/tl/generate/tl_writer_jni_cpp.cpp +++ b/submodules/ton/tonlib-src/tl/generate/tl_writer_jni_cpp.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "tl_writer_jni_cpp.h" @@ -24,8 +24,10 @@ namespace td { bool TD_TL_writer_jni_cpp::is_built_in_simple_type(const std::string &name) const { + assert(name != "function"); return name == "Bool" || name == "Int32" || name == "Int53" || name == "Int64" || name == "Double" || - name == "String" || name == "Bytes" || name == "SecureString" || name == "SecureBytes"; + name == "String" || name == "Bytes" || name == "SecureString" || name == "SecureBytes" || name == "Function" || + name == "Object"; } bool TD_TL_writer_jni_cpp::is_built_in_complex_type(const std::string &name) const { @@ -197,6 +199,7 @@ std::string TD_TL_writer_jni_cpp::gen_type_fetch(const std::string &field_name, const tl::tl_tree_type *child = static_cast(tree_type->children[0]); res = gen_vector_fetch(field_name, child, vars, parser_type); } else { + assert(gen_main_class_name(tree_type->type) != "function"); if (field_name == "") { return gen_main_class_name(tree_type->type) + "::fetch(env, p)"; } diff --git a/submodules/ton/tonlib-src/tl/generate/tl_writer_jni_h.cpp b/submodules/ton/tonlib-src/tl/generate/tl_writer_jni_h.cpp index 7e12246367..5c9896bd3b 100644 --- a/submodules/ton/tonlib-src/tl/generate/tl_writer_jni_h.cpp +++ b/submodules/ton/tonlib-src/tl/generate/tl_writer_jni_h.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "tl_writer_jni_h.h" @@ -24,7 +24,8 @@ namespace td { bool TD_TL_writer_jni_h::is_built_in_simple_type(const std::string &name) const { return name == "Bool" || name == "Int32" || name == "Int53" || name == "Int64" || name == "Double" || - name == "String" || name == "Bytes" || name == "SecureString" || name == "SecureBytes"; + name == "String" || name == "Bytes" || name == "SecureString" || name == "SecureBytes" || name == "Function" || + name == "Object"; } bool TD_TL_writer_jni_h::is_built_in_complex_type(const std::string &name) const { diff --git a/submodules/ton/tonlib-src/tl/generate/tl_writer_td.cpp b/submodules/ton/tonlib-src/tl/generate/tl_writer_td.cpp index dc4a98f787..dbcc025d50 100644 --- a/submodules/ton/tonlib-src/tl/generate/tl_writer_td.cpp +++ b/submodules/ton/tonlib-src/tl/generate/tl_writer_td.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "tl_writer_td.h" @@ -124,6 +124,12 @@ std::string TD_TL_writer::gen_class_name(std::string name) const { if (name == "Object") { //assert(false); } + if (name == "function") { + return "Function"; + } + if (name == "object") { + return "Object"; + } if (name == "#") { return "std::int32_t"; } diff --git a/submodules/ton/tonlib-src/ton/ton-types.h b/submodules/ton/tonlib-src/ton/ton-types.h index fac94dc769..a259c505d5 100644 --- a/submodules/ton/tonlib-src/ton/ton-types.h +++ b/submodules/ton/tonlib-src/ton/ton-types.h @@ -23,6 +23,9 @@ #include "td/utils/bits.h" #include "td/utils/Slice.h" #include "td/utils/UInt.h" +#include "td/utils/misc.h" + +#include namespace ton { @@ -140,7 +143,7 @@ struct AccountIdPrefixFull { std::string to_str() const { char buffer[64]; return std::string{ - buffer, (unsigned)snprintf(buffer, 63, "(%d,%016llx)", workchain, (unsigned long long)account_id_prefix)}; + buffer, (unsigned)snprintf(buffer, 63, "(%d,%016llx)", workchain, static_cast(account_id_prefix))}; } }; @@ -158,6 +161,9 @@ struct BlockId { explicit operator ShardIdFull() const { return ShardIdFull{workchain, shard}; } + ShardIdFull shard_full() const { + return ShardIdFull{workchain, shard}; + } bool is_valid() const { return workchain != workchainInvalid; } @@ -200,8 +206,8 @@ struct BlockId { } std::string to_str() const { char buffer[64]; - return std::string{buffer, - (unsigned)snprintf(buffer, 63, "(%d,%016llx,%u)", workchain, (unsigned long long)shard, seqno)}; + return std::string{buffer, (unsigned)snprintf(buffer, 63, "(%d,%016llx,%u)", workchain, + static_cast(shard), seqno)}; } }; @@ -274,6 +280,23 @@ struct BlockIdExt { std::string to_str() const { return id.to_str() + ':' + root_hash.to_hex() + ':' + file_hash.to_hex(); } + static td::Result from_str(td::CSlice s) { + BlockIdExt v; + char rh[65]; + char fh[65]; + auto r = sscanf(s.begin(), "(%d,%" SCNx64 ",%u):%64s:%64s", &v.id.workchain, &v.id.shard, &v.id.seqno, rh, fh); + if (r < 5) { + return td::Status::Error("failed to parse block id"); + } + if (strlen(rh) != 64 || strlen(fh) != 64) { + return td::Status::Error("failed to parse block id: bad roothash/filehash"); + } + TRY_RESULT(re, td::hex_decode(td::Slice(rh, 64))); + v.root_hash.as_slice().copy_from(td::Slice(re)); + TRY_RESULT(fe, td::hex_decode(td::Slice(fh, 64))); + v.file_hash.as_slice().copy_from(td::Slice(fe)); + return v; + } }; struct ZeroStateIdExt { diff --git a/submodules/ton/tonlib-src/tonlib/test/offline.cpp b/submodules/ton/tonlib-src/tonlib/test/offline.cpp index c615397e3c..223c8edad2 100644 --- a/submodules/ton/tonlib-src/tonlib/test/offline.cpp +++ b/submodules/ton/tonlib-src/tonlib/test/offline.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "block/block.h" @@ -35,6 +35,7 @@ #include "td/utils/benchmark.h" #include "td/utils/filesystem.h" #include "td/utils/optional.h" +#include "td/utils/overloaded.h" #include "td/utils/port/path.h" #include "td/utils/PathView.h" #include "td/utils/tests.h" @@ -60,6 +61,23 @@ TEST(Tonlib, CellString) { } }; +TEST(Tonlib, Text) { + for (unsigned size : + {0, 1, 7, 8, 35, 127, 128, 255, 256, (int)vm::CellText::max_bytes - 1, (int)vm::CellText::max_bytes}) { + auto str = td::rand_string('a', 'z', size); + for (unsigned head : {16, 17, 127, 35 * 8, 127 * 8, 1023, 1024}) { + vm::CellBuilder cb; + vm::CellText::store(cb, str, head).ensure(); + auto cs = vm::load_cell_slice(cb.finalize()); + auto cs2 = cs; + cs.print_rec(std::cerr); + CHECK(block::gen::t_Text.validate_exact_upto(1024, cs2)); + auto got_str = vm::CellText::load(cs).move_as_ok(); + ASSERT_EQ(str, got_str); + } + } +}; + using namespace tonlib; TEST(Tonlib, PublicKey) { @@ -126,7 +144,10 @@ TEST(Tonlib, InitClose) { )abc"; sync_send(client, make_object(cfg(bad_config.str()))).ensure_error(); - sync_send(client, make_object()).ensure_error(); + auto address = sync_send(client, make_object( + make_object(), 0)) + .move_as_ok(); + sync_send(client, make_object(std::move(address))).ensure_error(); sync_send(client, make_object()).ensure(); sync_send(client, make_object()).ensure_error(); sync_send(client, make_object(make_object(nullptr, dir(".")))) @@ -134,30 +155,70 @@ TEST(Tonlib, InitClose) { } } -TEST(Tonlib, SimpleEncryption) { +template +void test_encryption() { std::string secret = "secret"; { std::string data = "some private data"; std::string wrong_secret = "wrong secret"; - auto encrypted_data = SimpleEncryption::encrypt_data(data, secret); + auto encrypted_data = Encryption::encrypt_data(data, secret); LOG(ERROR) << encrypted_data.size(); - auto decrypted_data = SimpleEncryption::decrypt_data(encrypted_data, secret).move_as_ok(); + auto decrypted_data = Encryption::decrypt_data(encrypted_data, secret).move_as_ok(); CHECK(data == decrypted_data); - SimpleEncryption::decrypt_data(encrypted_data, wrong_secret).ensure_error(); - SimpleEncryption::decrypt_data("", secret).ensure_error(); - SimpleEncryption::decrypt_data(std::string(32, 'a'), secret).ensure_error(); - SimpleEncryption::decrypt_data(std::string(33, 'a'), secret).ensure_error(); - SimpleEncryption::decrypt_data(std::string(64, 'a'), secret).ensure_error(); - SimpleEncryption::decrypt_data(std::string(128, 'a'), secret).ensure_error(); + Encryption::decrypt_data(encrypted_data, wrong_secret).ensure_error(); + Encryption::decrypt_data("", secret).ensure_error(); + Encryption::decrypt_data(std::string(32, 'a'), secret).ensure_error(); + Encryption::decrypt_data(std::string(33, 'a'), secret).ensure_error(); + Encryption::decrypt_data(std::string(64, 'a'), secret).ensure_error(); + Encryption::decrypt_data(std::string(128, 'a'), secret).ensure_error(); } for (size_t i = 0; i < 255; i++) { auto data = td::rand_string('a', 'z', static_cast(i)); - auto encrypted_data = SimpleEncryption::encrypt_data(data, secret); - auto decrypted_data = SimpleEncryption::decrypt_data(encrypted_data, secret).move_as_ok(); + auto encrypted_data = Encryption::encrypt_data(data, secret); + auto decrypted_data = Encryption::decrypt_data(encrypted_data, secret).move_as_ok(); CHECK(data == decrypted_data); } } +TEST(Tonlib, SimpleEncryption) { + test_encryption(); +} + +TEST(Tonlib, SimpleEncryptionV2) { + test_encryption(); +} + +TEST(Tonlib, SimpleEncryptionAsym) { + auto private_key = td::Ed25519::generate_private_key().move_as_ok(); + auto public_key = private_key.get_public_key().move_as_ok(); + auto other_private_key = td::Ed25519::generate_private_key().move_as_ok(); + auto other_public_key = private_key.get_public_key().move_as_ok(); + auto wrong_private_key = td::Ed25519::generate_private_key().move_as_ok(); + { + std::string data = "some private data"; + auto encrypted_data = SimpleEncryptionV2::encrypt_data(data, public_key, other_private_key).move_as_ok(); + LOG(ERROR) << encrypted_data.size(); + auto decrypted_data = SimpleEncryptionV2::decrypt_data(encrypted_data, private_key).move_as_ok(); + CHECK(data == decrypted_data); + auto decrypted_data2 = SimpleEncryptionV2::decrypt_data(encrypted_data, other_private_key).move_as_ok(); + CHECK(data == decrypted_data2); + SimpleEncryptionV2::decrypt_data(encrypted_data, wrong_private_key).ensure_error(); + SimpleEncryptionV2::decrypt_data("", private_key).ensure_error(); + SimpleEncryptionV2::decrypt_data(std::string(32, 'a'), private_key).ensure_error(); + SimpleEncryptionV2::decrypt_data(std::string(33, 'a'), private_key).ensure_error(); + SimpleEncryptionV2::decrypt_data(std::string(64, 'a'), private_key).ensure_error(); + SimpleEncryptionV2::decrypt_data(std::string(128, 'a'), private_key).ensure_error(); + } + + for (size_t i = 0; i < 255; i++) { + auto data = td::rand_string('a', 'z', static_cast(i)); + auto encrypted_data = SimpleEncryptionV2::encrypt_data(data, public_key, other_private_key).move_as_ok(); + auto decrypted_data = SimpleEncryptionV2::decrypt_data(encrypted_data, private_key).move_as_ok(); + CHECK(data == decrypted_data); + auto decrypted_data2 = SimpleEncryptionV2::decrypt_data(encrypted_data, other_private_key).move_as_ok(); + CHECK(data == decrypted_data2); + } +} class MnemonicBench : public td::Benchmark { public: @@ -437,4 +498,130 @@ TEST(Tonlib, KeysApi) { .move_as_ok(); CHECK(new_imported_key->public_key_ == key->public_key_); CHECK(new_imported_key->secret_ != key->secret_); + + auto exported_raw_key = + sync_send(client, make_object(make_object( + make_object(key->public_key_, new_imported_key->secret_.copy()), + new_local_password.copy()))) + .move_as_ok(); + sync_send(client, make_object( + make_object(new_imported_key->public_key_, new_imported_key->secret_.copy()))) + .move_as_ok(); + td::Ed25519::PrivateKey pkey(exported_raw_key->data_.copy()); + auto raw_imported_key = sync_send(client, make_object(new_local_password.copy(), + std::move(exported_raw_key))) + .move_as_ok(); + + CHECK(raw_imported_key->public_key_ == key->public_key_); + CHECK(raw_imported_key->secret_ != key->secret_); + + auto other_public_key = td::Ed25519::generate_private_key().move_as_ok().get_public_key().move_as_ok(); + std::string text = "hello world"; + + std::vector> elements; + elements.push_back(make_object( + SimpleEncryptionV2::encrypt_data(text, other_public_key, pkey).move_as_ok().as_slice().str())); + + auto decrypted = + sync_send(client, make_object( + make_object( + make_object(key->public_key_, raw_imported_key->secret_.copy()), + new_local_password.copy()), + make_object(std::move(elements)))) + .move_as_ok(); + + downcast_call(*decrypted->elements_[0], + td::overloaded([](auto &) { UNREACHABLE(); }, + [&](tonlib_api::msg_dataDecryptedText &decrypted) { CHECK(decrypted.text_ == text); })); +} + +TEST(Tonlib, ConfigCache) { + using tonlib_api::make_object; + Client client; + + td::mkdir("testdir").ignore(); + // init + sync_send(client, make_object(make_object( + nullptr, make_object("testdir")))) + .ensure(); + + auto testnet = R"abc({ + "liteservers": [ + ], + "validator": { + "@type": "validator.config.global", + "zero_state": { + "workchain": -1, + "shard": -9223372036854775808, + "seqno": 0, + "root_hash": "VCSXxDHhTALFxReyTZRd8E4Ya3ySOmpOWAS4rBX9XBY=", + "file_hash": "eh9yveSz1qMdJ7mOsO+I+H77jkLr9NpAuEkoJuseXBo=" + } + } +})abc"; + auto testnet2 = R"abc({ + "liteservers": [ + ], + "validator": { + "@type": "validator.config.global", + "zero_state": { + "workchain": -1, + "shard": -9223372036854775808, + "seqno": 0, + "root_hash": "VXSXxDHhTALFxReyTZRd8E4Ya3ySOmpOWAS4rBX9XBY=", + "file_hash": "eh9yveSz1qMdJ7mOsO+I+H77jkLr9NpAuEkoJuseXBo=" + } + } +})abc"; + auto testnet3 = R"abc({ + "liteservers": [ + ], + "validator": { + "@type": "validator.config.global", + "zero_state": { + "workchain": -1, + "shard": -9223372036854775808, + "seqno": 0, + "root_hash": "ZXSXxDHhTALFxReyTZRd8E4Ya3ySOmpOWAS4rBX9XBY=", + "file_hash": "eh9yveSz1qMdJ7mOsO+I+H77jkLr9NpAuEkoJuseXBo=" + } + } +})abc"; + auto bad = R"abc({ + "liteservers": [ + ], + "validator": { + "@type": "validator.config.global", + "zero_state": { + "workchain": -1, + "shard": -9223372036854775808, + "seqno": 0, + "file_hash": "eh9yveSz1qMdJ7mOsO+I+H77jkLr9NpAuEkoJuseXBo=" + } + } +})abc"; + sync_send(client, + make_object(make_object(bad, "", true, false))) + .ensure_error(); + + sync_send(client, + make_object(make_object(testnet, "", true, false))) + .ensure(); + sync_send(client, + make_object(make_object(testnet2, "", true, false))) + .ensure(); + sync_send(client, + make_object(make_object(testnet3, "", true, false))) + .ensure(); + + sync_send(client, make_object( + make_object(testnet2, "testnet", true, false))) + .ensure_error(); + + sync_send(client, make_object( + make_object(testnet2, "testnet2", true, false))) + .ensure(); + sync_send(client, make_object( + make_object(testnet3, "testnet2", true, false))) + .ensure_error(); } diff --git a/submodules/ton/tonlib-src/tonlib/test/online.cpp b/submodules/ton/tonlib-src/tonlib/test/online.cpp index 8eabc452e2..d6d4a8944a 100644 --- a/submodules/ton/tonlib-src/tonlib/test/online.cpp +++ b/submodules/ton/tonlib-src/tonlib/test/online.cpp @@ -23,7 +23,7 @@ exception statement from your version. If you delete this exception statement from all source files in the program, then also delete it here. - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "adnl/adnl-ext-client.h" #include "tl-utils/tl-utils.hpp" @@ -37,6 +37,7 @@ #include "Ed25519.h" #include "smc-envelope/GenericAccount.h" +#include "smc-envelope/ManualDns.h" #include "smc-envelope/MultisigWallet.h" #include "smc-envelope/TestGiver.h" #include "smc-envelope/TestWallet.h" @@ -108,6 +109,10 @@ struct Key { struct Wallet { std::string address; Key key; + + auto get_address() const { + return tonlib_api::make_object(address); + } }; struct TransactionId { @@ -116,7 +121,7 @@ struct TransactionId { }; struct AccountState { - enum Type { Empty, Wallet, Unknown } type{Empty}; + enum Type { Empty, Wallet, Dns, Unknown } type{Empty}; td::int64 sync_utime{-1}; td::int64 balance{-1}; TransactionId last_transaction_id; @@ -136,8 +141,17 @@ void sync(Client& client) { static td::uint32 default_wallet_id{0}; std::string wallet_address(Client& client, const Key& key) { return sync_send(client, - make_object( - make_object(key.public_key, default_wallet_id))) + make_object( + make_object(key.public_key, default_wallet_id), 0)) + .move_as_ok() + ->account_address_; +} + +std::string highload_wallet_address(Client& client, const Key& key) { + return sync_send(client, make_object( + make_object(key.public_key, + default_wallet_id), + 1 /*TODO: guess revision!*/)) .move_as_ok() ->account_address_; } @@ -148,35 +162,31 @@ Wallet import_wallet_from_pkey(Client& client, std::string pkey, std::string pas make_object(td::SecureString(pkey)))) .move_as_ok(); Wallet wallet{"", {key->public_key_, std::move(key->secret_)}}; - wallet.address = wallet_address(client, wallet.key); + wallet.address = highload_wallet_address(client, wallet.key); return wallet; } -std::string test_giver_address(Client& client) { - using tonlib_api::make_object; - return sync_send(client, make_object()).move_as_ok()->account_address_; -} - AccountState get_account_state(Client& client, std::string address) { - auto generic_state = sync_send(client, tonlib_api::make_object( - tonlib_api::make_object(address))) - .move_as_ok(); + auto state = sync_send(client, tonlib_api::make_object( + tonlib_api::make_object(address))) + .move_as_ok(); AccountState res; - tonlib_api::downcast_call(*generic_state, [&](auto& state) { - res.balance = state.account_state_->balance_; - res.sync_utime = state.account_state_->sync_utime_; - res.last_transaction_id.lt = state.account_state_->last_transaction_id_->lt_; - res.last_transaction_id.hash = state.account_state_->last_transaction_id_->hash_; - }); + res.balance = state->balance_; + res.sync_utime = state->sync_utime_; + res.last_transaction_id.lt = state->last_transaction_id_->lt_; + res.last_transaction_id.hash = state->last_transaction_id_->hash_; res.address = address; - switch (generic_state->get_id()) { - case tonlib_api::generic_accountStateUninited::ID: + switch (state->account_state_->get_id()) { + case tonlib_api::uninited_accountState::ID: res.type = AccountState::Empty; break; - case tonlib_api::generic_accountStateWalletV3::ID: - case tonlib_api::generic_accountStateWallet::ID: + case tonlib_api::wallet_v3_accountState::ID: + case tonlib_api::wallet_accountState::ID: res.type = AccountState::Wallet; break; + case tonlib_api::dns_accountState::ID: + res.type = AccountState::Dns; + break; default: res.type = AccountState::Unknown; break; @@ -219,13 +229,31 @@ struct QueryInfo { }; td::Result create_send_grams_query(Client& client, const Wallet& source, std::string destination, - td::int64 amount, std::string message, bool force = false, int timeout = 0, - bool fake = false) { - auto r_id = sync_send(client, tonlib_api::make_object( - fake ? source.key.get_fake_input_key() : source.key.get_input_key(), - tonlib_api::make_object(source.address), - tonlib_api::make_object(destination), amount, timeout, - force, std::move(message))); + td::int64 amount, bool encrypted, std::string message, bool force = false, + int timeout = 0, bool fake = false) { + std::vector> msgs; + tonlib_api::object_ptr data; + if (encrypted) { + data = tonlib_api::make_object(std::move(message)); + } else { + data = tonlib_api::make_object(std::move(message)); + } + msgs.push_back(tonlib_api::make_object( + tonlib_api::make_object(destination), amount, std::move(data))); + + auto r_id = + sync_send(client, tonlib_api::make_object( + fake ? source.key.get_fake_input_key() : source.key.get_input_key(), source.get_address(), + timeout, tonlib_api::make_object(std::move(msgs), force))); + TRY_RESULT(id, std::move(r_id)); + return QueryId{id->id_}; +} + +td::Result create_update_dns_query(Client& client, const Wallet& dns, + std::vector> entries) { + using namespace ton::tonlib_api; + auto r_id = sync_send(client, make_object(dns.key.get_input_key(), dns.get_address(), 60, + make_object(std::move(entries)))); TRY_RESULT(id, std::move(r_id)); return QueryId{id->id_}; } @@ -242,7 +270,11 @@ td::Result create_raw_query(Client& client, std::string source, std::st std::pair query_estimate_fees(Client& client, QueryId query_id, bool ignore_chksig = false) { auto fees = sync_send(client, tonlib_api::make_object(query_id.id, ignore_chksig)) .move_as_ok(); - return std::make_pair(to_fee(fees->source_fees_), to_fee(fees->destination_fees_)); + Fee second; + if (!fees->destination_fees_.empty()) { + second = to_fee(fees->destination_fees_[0]); + } + return std::make_pair(to_fee(fees->source_fees_), second); } void query_send(Client& client, QueryId query_id) { @@ -266,26 +298,45 @@ td::Result wait_state_change(Client& client, const AccountState& o } }; -td::Result> get_transactions(Client& client, std::string address, +td::Result> get_transactions(Client& client, + td::optional wallet, + std::string address, const TransactionId& from) { auto got_transactions = sync_send(client, make_object( + wallet ? wallet.value()->key.get_input_key() : nullptr, make_object(address), make_object(from.lt, from.hash))) .move_as_ok(); return std::move(got_transactions); } -td::Status transfer_grams(Client& client, const Wallet& wallet, std::string address, td::int64 amount) { +std::string read_text(tonlib_api::msg_Data& data) { + std::string text; + downcast_call(data, td::overloaded([](auto& other) {}, [&](tonlib_api::msg_dataText& data) { text = data.text_; }, + [&](tonlib_api::msg_dataDecryptedText& data) { text = data.text_; })); + return text; +} + +td::Status transfer_grams(Client& client, const Wallet& wallet, std::string address, td::int64 amount, + bool fast = false) { auto src_state = get_account_state(client, wallet.address); auto dst_state = get_account_state(client, address); auto message = td::rand_string('a', 'z', 500); LOG(INFO) << "Transfer: create query " << (double)amount / Gramm << " from " << wallet.address << " to " << address; - auto r_query_id = create_send_grams_query(client, wallet, address, amount, message); + bool encrypt = true; + auto r_query_id = create_send_grams_query(client, wallet, address, amount, encrypt, message, fast); + if (r_query_id.is_error()) { + LOG(INFO) << "Send query WITHOUT message encryption " << r_query_id.error(); + encrypt = false; + r_query_id = create_send_grams_query(client, wallet, address, amount, encrypt, message, fast); + } else { + LOG(INFO) << "Send query WITH message encryption"; + } if (r_query_id.is_error() && td::begins_with(r_query_id.error().message(), "DANGEROUS_TRANSACTION")) { ASSERT_TRUE(dst_state.type == AccountState::Empty); LOG(INFO) << "Transfer: recreate query due to DANGEROUS_TRANSACTION error"; - r_query_id = create_send_grams_query(client, wallet, address, amount, message, true); + r_query_id = create_send_grams_query(client, wallet, address, amount, false, message, true); } r_query_id.ensure(); @@ -304,6 +355,9 @@ td::Status transfer_grams(Client& client, const Wallet& wallet, std::string addr LOG(INFO) << "Transfer: send query"; query_send(client, query_id); + if (fast) { + return td::Status::OK(); + } td::Timer timer; TRY_RESULT(new_src_state, wait_state_change(client, src_state, query_info.valid_until)); LOG(INFO) << "Transfer: reached source in " << timer; @@ -311,12 +365,12 @@ td::Status transfer_grams(Client& client, const Wallet& wallet, std::string addr td::int64 lt; td::int64 first_fee; { - auto tr = get_transactions(client, src_state.address, new_src_state.last_transaction_id).move_as_ok(); + auto tr = get_transactions(client, &wallet, src_state.address, new_src_state.last_transaction_id).move_as_ok(); CHECK(tr->transactions_.size() > 0); const auto& txn = tr->transactions_[0]; CHECK(txn->in_msg_->body_hash_ == query_info.body_hash); ASSERT_EQ(1u, txn->out_msgs_.size()); - ASSERT_EQ(message, txn->out_msgs_[0]->message_); + ASSERT_EQ(message, read_text(*txn->out_msgs_[0]->msg_data_)); lt = txn->out_msgs_[0]->created_lt_; auto fee_difference = fees.first.sum() - txn->fee_; first_fee = txn->fee_; @@ -331,7 +385,7 @@ td::Status transfer_grams(Client& client, const Wallet& wallet, std::string addr LOG(INFO) << "Transfer: reached destination in " << timer; { - auto tr = get_transactions(client, dst_state.address, new_dst_state.last_transaction_id).move_as_ok(); + auto tr = get_transactions(client, {}, dst_state.address, new_dst_state.last_transaction_id).move_as_ok(); CHECK(tr->transactions_.size() > 0); const auto& txn = tr->transactions_[0]; ASSERT_EQ(lt, txn->in_msg_->created_lt_); @@ -341,7 +395,9 @@ td::Status transfer_grams(Client& client, const Wallet& wallet, std::string addr ASSERT_EQ(new_src_state.address, txn->in_msg_->source_); } ASSERT_EQ(new_src_state.address, txn->in_msg_->source_); - ASSERT_EQ(message, txn->in_msg_->message_); + if (!encrypt) { + ASSERT_EQ(message, read_text(*txn->in_msg_->msg_data_)); + } auto fee_difference = fees.second.sum() - txn->fee_; auto desc = PSTRING() << fee_difference << " storage:[" << fees.second.storage_fee << " vs " << txn->storage_fee_ << "] other:[" << fees.second.sum() - fees.second.storage_fee << " vs " << txn->other_fee_ @@ -361,9 +417,10 @@ Wallet create_empty_wallet(Client& client) { Wallet wallet{"", {key->public_key_, std::move(key->secret_)}}; auto account_address = - sync_send(client, - make_object( - make_object(wallet.key.public_key, default_wallet_id))) + sync_send( + client, + make_object( + make_object(wallet.key.public_key, default_wallet_id), 0)) .move_as_ok(); wallet.address = account_address->account_address_; @@ -376,31 +433,33 @@ Wallet create_empty_wallet(Client& client) { return wallet; } -void dump_transaction_history(Client& client, std::string address) { +Wallet create_empty_dns(Client& client) { using tonlib_api::make_object; - auto state = sync_send(client, make_object()).move_as_ok(); - auto tid = std::move(state->last_transaction_id_); - int cnt = 0; - while (tid->lt_ != 0) { - auto lt = tid->lt_; - auto got_transactions = sync_send(client, make_object( - make_object(address), std::move(tid))) - .move_as_ok(); - CHECK(got_transactions->transactions_.size() > 0); - CHECK(got_transactions->previous_transaction_id_->lt_ < lt); - for (auto& txn : got_transactions->transactions_) { - LOG(ERROR) << to_string(txn); - cnt++; - } - tid = std::move(got_transactions->previous_transaction_id_); - } - LOG(ERROR) << cnt; + auto key = sync_send(client, make_object(td::SecureString("local"), td::SecureString(), + td::SecureString())) + .move_as_ok(); + Wallet dns{"", {key->public_key_, std::move(key->secret_)}}; + + auto account_address = + sync_send(client, make_object( + make_object(dns.key.public_key, default_wallet_id), 0)) + .move_as_ok(); + + dns.address = account_address->account_address_; + + // get state of empty account + auto state = get_account_state(client, dns.address); + ASSERT_EQ(-1, state.balance); + ASSERT_EQ(AccountState::Empty, state.type); + + return dns; } void test_estimate_fees_without_key(Client& client, const Wallet& wallet_a, const Wallet& wallet_b) { LOG(ERROR) << " SUBTEST: estimate fees without key"; { - auto query_id = create_send_grams_query(client, wallet_a, wallet_b.address, 0, "???", true, 0, true).move_as_ok(); + auto query_id = + create_send_grams_query(client, wallet_a, wallet_b.address, 0, false, "???", true, 0, true).move_as_ok(); auto fees1 = query_estimate_fees(client, query_id, false); auto fees2 = query_estimate_fees(client, query_id, true); LOG(INFO) << "Fee without ignore_chksig\t" << fees1; @@ -451,6 +510,7 @@ void test_multisig(Client& client, const Wallet& giver_wallet) { int n = 16; int k = 10; + td::uint32 wallet_id = 7; std::vector private_keys; for (int i = 0; i < n; i++) { private_keys.push_back(td::Ed25519::generate_private_key().move_as_ok()); @@ -458,6 +518,7 @@ void test_multisig(Client& client, const Wallet& giver_wallet) { auto ms = ton::MultisigWallet::create(); auto init_data = ms->create_init_data( + wallet_id, td::transform(private_keys, [](const auto& pk) { return pk.get_public_key().move_as_ok().as_octet_string(); }), k); ms = ton::MultisigWallet::create(init_data); @@ -472,7 +533,7 @@ void test_multisig(Client& client, const Wallet& giver_wallet) { ton::GenericAccount::store_int_message(icb, block::StdAddress::parse(giver_wallet.address).move_as_ok(), 1); icb.store_bytes("\0\0\0\0", 4); vm::CellString::store(icb, "Greatings from multisig", 35 * 8).ensure(); - ton::MultisigWallet::QueryBuilder qb(-1 - i, icb.finalize()); + ton::MultisigWallet::QueryBuilder qb(wallet_id, -1 - i, icb.finalize()); for (int i = 0; i < k - 1; i++) { qb.sign(i, private_keys[i]); } @@ -493,6 +554,66 @@ void test_multisig(Client& client, const Wallet& giver_wallet) { } } +void dns_resolve(Client& client, const Wallet& dns, std::string name) { + using namespace ton::tonlib_api; + auto address = dns.get_address(); + auto resolved = + sync_send(client, make_object<::ton::tonlib_api::dns_resolve>(std::move(address), name, 1, 4)).move_as_ok(); + CHECK(resolved->entries_.size() == 1); + LOG(INFO) << to_string(resolved); + LOG(INFO) << "OK"; +} + +void test_dns(Client& client, const Wallet& giver_wallet) { + auto A = create_empty_dns(client); + auto A_B = create_empty_dns(client); + auto A_B_C = create_empty_dns(client); + transfer_grams(client, giver_wallet, A.address, 1 * Gramm, true).ensure(); + transfer_grams(client, giver_wallet, A_B.address, 1 * Gramm, true).ensure(); + transfer_grams(client, giver_wallet, A_B_C.address, 1 * Gramm, true).ensure(); + + using namespace ton::tonlib_api; + std::vector> actions; + + actions.push_back(make_object( + make_object("A", -1, make_object(A_B.get_address())))); + auto init_A = create_update_dns_query(client, A, std::move(actions)).move_as_ok(); + actions.push_back(make_object( + make_object("B", -1, make_object(A_B_C.get_address())))); + auto init_A_B = create_update_dns_query(client, A_B, std::move(actions)).move_as_ok(); + actions.push_back( + make_object(make_object("C", 1, make_object("Hello dns")))); + auto init_A_B_C = create_update_dns_query(client, A_B_C, std::move(actions)).move_as_ok(); + + LOG(INFO) << "Send dns init queries"; + ::query_send(client, init_A); + ::query_send(client, init_A_B); + ::query_send(client, init_A_B_C); + + auto wait = [&](auto& query, auto& dns) { + auto info = query_get_info(client, query); + LOG(INFO) << "Wait till dns " << dns.address << " is inited " << info.valid_until; + while (true) { + auto state = get_account_state(client, dns.address); + LOG(INFO) << "Account type: " << state.type << " " << state.sync_utime; + if (state.type == ::AccountState::Dns) { + break; + } + if (state.sync_utime >= info.valid_until) { + LOG(FATAL) << "Query expired"; + } + LOG(INFO) << "time left to wait: " << td::format::as_time(info.valid_until - state.sync_utime); + client.receive(1); + } + }; + wait(init_A, A); + wait(init_A_B, A_B); + wait(init_A_B_C, A_B_C); + + // search "C.B.A" + ::dns_resolve(client, A, "C.B.A"); +} + int main(int argc, char* argv[]) { td::set_default_failure_signal_handler(); using tonlib_api::make_object; @@ -533,14 +654,12 @@ int main(int argc, char* argv[]) { Client client; { - auto info = sync_send(client, make_object( - make_object(global_config_str, "", false, false))) + auto info = sync_send(client, make_object(make_object( + make_object(global_config_str, "", false, false), + make_object(keystore_dir)))) .move_as_ok(); - default_wallet_id = static_cast(info->default_wallet_id_); - sync_send(client, make_object(make_object( - make_object(global_config_str, "", false, false), - make_object(keystore_dir)))) - .ensure(); + default_wallet_id = static_cast(info->config_info_->default_wallet_id_); + LOG(ERROR) << default_wallet_id; } // wait till client is synchronized with blockchain. @@ -550,6 +669,7 @@ int main(int argc, char* argv[]) { // give wallet with some test grams to run test auto giver_wallet = import_wallet_from_pkey(client, giver_key_str, giver_key_pwd); + test_dns(client, giver_wallet); test_back_and_forth_transfer(client, giver_wallet, false); test_back_and_forth_transfer(client, giver_wallet, true); test_multisig(client, giver_wallet); diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/KeyStorage.cpp b/submodules/ton/tonlib-src/tonlib/tonlib/KeyStorage.cpp index f1ac827156..cd2a73bc01 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/KeyStorage.cpp +++ b/submodules/ton/tonlib-src/tonlib/tonlib/KeyStorage.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "KeyStorage.h" @@ -179,6 +179,11 @@ td::Result KeyStorage::export_encrypted_key(In return ExportedEncryptedKey{std::move(res.encrypted_data)}; } +td::Result KeyStorage::export_unencrypted_key(InputKey input_key) { + TRY_RESULT(decrypted_key, export_decrypted_key(std::move(input_key))); + return ExportedUnencryptedKey{decrypted_key.private_key.as_octet_string()}; +} + td::Result KeyStorage::import_encrypted_key(td::Slice local_password, td::Slice key_password, ExportedEncryptedKey exported_key) { EncryptedKey encrypted_key{std::move(exported_key.data), td::Ed25519::PublicKey(td::SecureString()), @@ -187,6 +192,14 @@ td::Result KeyStorage::import_encrypted_key(td::Slice local_pas return save_key(std::move(decrypted_key), local_password); } +td::Result KeyStorage::import_unencrypted_key(td::Slice local_password, + ExportedUnencryptedKey exported_key) { + RawDecryptedKey raw_key; + raw_key.private_key = std::move(exported_key.data); + DecryptedKey key(std::move(raw_key)); + return save_key(std::move(key), local_password); +} + KeyStorage::PrivateKey KeyStorage::fake_private_key() { return PrivateKey{td::SecureString(32, 0)}; } diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/KeyStorage.h b/submodules/ton/tonlib-src/tonlib/tonlib/KeyStorage.h index 38478bf1f3..9d012ccdd5 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/KeyStorage.h +++ b/submodules/ton/tonlib-src/tonlib/tonlib/KeyStorage.h @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once @@ -46,6 +46,9 @@ class KeyStorage { struct ExportedEncryptedKey { td::SecureString data; }; + struct ExportedUnencryptedKey { + td::SecureString data; + }; struct PrivateKey { td::SecureString private_key; }; @@ -57,6 +60,7 @@ class KeyStorage { td::Result export_key(InputKey input_key); td::Result export_pem_key(InputKey input_key, td::Slice key_password); td::Result export_encrypted_key(InputKey input_key, td::Slice key_password); + td::Result export_unencrypted_key(InputKey input_key); td::Result change_local_password(InputKey input_key, td::Slice new_local_password); td::Status delete_key(const Key& key); @@ -66,6 +70,7 @@ class KeyStorage { td::Result import_pem_key(td::Slice local_password, td::Slice key_password, ExportedPemKey exported_key); td::Result import_encrypted_key(td::Slice local_password, td::Slice key_password, ExportedEncryptedKey exported_key); + td::Result import_unencrypted_key(td::Slice local_password, ExportedUnencryptedKey exported_key); td::Result load_private_key(InputKey input_key); diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/KeyValue.cpp b/submodules/ton/tonlib-src/tonlib/tonlib/KeyValue.cpp index ccf9a38372..cdb0f5eeee 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/KeyValue.cpp +++ b/submodules/ton/tonlib-src/tonlib/tonlib/KeyValue.cpp @@ -1,3 +1,21 @@ +/* + This file is part of TON Blockchain Library. + + TON Blockchain Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + TON Blockchain Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with TON Blockchain Library. If not, see . + + Copyright 2017-2020 Telegram Systems LLP +*/ #include "KeyValue.h" #include "td/utils/filesystem.h" @@ -106,11 +124,7 @@ class KeyValueInmemory : public KeyValue { } private: - class Cmp : public std::less<> { - public: - using is_transparent = void; - }; - std::map map_; + std::map> map_; }; } // namespace detail diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/KeyValue.h b/submodules/ton/tonlib-src/tonlib/tonlib/KeyValue.h index 7d2020acc9..33aef44e7f 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/KeyValue.h +++ b/submodules/ton/tonlib-src/tonlib/tonlib/KeyValue.h @@ -1,3 +1,21 @@ +/* + This file is part of TON Blockchain Library. + + TON Blockchain Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + TON Blockchain Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with TON Blockchain Library. If not, see . + + Copyright 2017-2020 Telegram Systems LLP +*/ #pragma once #include "td/utils/SharedSlice.h" #include "td/utils/Slice.h" diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/LastConfig.h b/submodules/ton/tonlib-src/tonlib/tonlib/LastConfig.h index 2e0cf2a399..514b4a5953 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/LastConfig.h +++ b/submodules/ton/tonlib-src/tonlib/tonlib/LastConfig.h @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once #include "td/actor/actor.h" @@ -54,7 +54,7 @@ class LastConfig : public td::actor::Actor { QueryState get_config_state_{QueryState::Empty}; std::vector> promises_; - std::vector params_{18, 20, 21, 24, 25}; + std::vector params_{4, 18, 20, 21, 24, 25}; void with_last_block(td::Result r_last_block); void on_config(td::Result> r_config); diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/TonlibClient.cpp b/submodules/ton/tonlib-src/tonlib/tonlib/TonlibClient.cpp index 95a089d720..f031596167 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/TonlibClient.cpp +++ b/submodules/ton/tonlib-src/tonlib/tonlib/TonlibClient.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "TonlibClient.h" @@ -29,10 +29,14 @@ #include "tonlib/TonlibError.h" #include "smc-envelope/GenericAccount.h" +#include "smc-envelope/ManualDns.h" #include "smc-envelope/TestWallet.h" #include "smc-envelope/Wallet.h" #include "smc-envelope/WalletV3.h" +#include "smc-envelope/HighloadWallet.h" +#include "smc-envelope/HighloadWalletV2.h" #include "smc-envelope/TestGiver.h" +#include "smc-envelope/SmartContractCode.h" #include "auto/tl/tonlib_api.hpp" #include "block/block-auto.h" @@ -50,22 +54,61 @@ #include "td/utils/tests.h" #include "td/utils/port/path.h" +#include "common/util.h" + namespace tonlib { namespace int_api { struct GetAccountState { block::StdAddress address; + td::optional block_id; using ReturnType = td::unique_ptr; }; + +struct RemoteRunSmcMethod { + block::StdAddress address; + td::optional block_id; + ton::SmartContract::Args args; + bool need_result{false}; + + using ReturnType = RemoteRunSmcMethodReturnType; +}; + +struct RemoteRunSmcMethodReturnType { + ton::SmartContract::State smc_state; + ton::BlockIdExt block_id; + // result + // c7 + // libs +}; + struct GetPrivateKey { KeyStorage::InputKey input_key; using ReturnType = KeyStorage::PrivateKey; }; +struct GetDnsResolver { + using ReturnType = block::StdAddress; +}; struct SendMessage { td::Ref message; using ReturnType = td::Unit; }; } // namespace int_api +template +R downcast_call2(O&& o, F&& f, R res = {}) { + downcast_call(o, [&](auto& x) { res = f(x); }); + return res; +} + +auto to_tonlib_api(const ton::BlockIdExt& blk) { + return tonlib_api::make_object( + blk.id.workchain, blk.id.shard, blk.id.seqno, blk.root_hash.as_slice().str(), blk.file_hash.as_slice().str()); +} + +tonlib_api::object_ptr to_tonlib_api(const TonlibClient::FullConfig& full_config) { + return tonlib_api::make_object(full_config.wallet_id); +} + class TonlibQueryActor : public td::actor::Actor { public: TonlibQueryActor(td::actor::ActorShared client) : client_(std::move(client)) { @@ -95,6 +138,16 @@ static block::AccountState create_account_state(ton::tl_object_ptrstate_); return res; } +static block::AccountState create_account_state(ton::tl_object_ptr& from) { + block::AccountState res; + res.blk = ton::create_block_id(from->id_); + res.shard_blk = ton::create_block_id(from->shardblk_); + res.shard_proof = std::move(from->shard_proof_); + res.proof = std::move(from->proof_); + res.state = std::move(from->state_proof_); + res.is_virtualized = from->mode_ > 0; + return res; +} struct RawAccountState { td::int64 balance = -1; @@ -106,6 +159,7 @@ struct RawAccountState { td::Ref state; std::string frozen_hash; block::AccountState::Info info; + ton::BlockIdExt block_id; }; tonlib_api::object_ptr empty_transaction_id() { @@ -125,12 +179,11 @@ class AccountState { public: AccountState(block::StdAddress address, RawAccountState&& raw, td::uint32 wallet_id) : address_(std::move(address)), raw_(std::move(raw)), wallet_id_(wallet_id) { - wallet_type_ = guess_type(); + guess_type(); } auto to_uninited_accountState() const { - return tonlib_api::make_object(get_balance(), to_transaction_id(raw().info), - raw().frozen_hash, get_sync_time()); + return tonlib_api::make_object(raw().frozen_hash); } td::Result> to_raw_accountState() const { @@ -143,9 +196,22 @@ class AccountState { if (state.data.not_null()) { data = to_bytes(state.data); } - return tonlib_api::make_object(get_balance(), std::move(code), std::move(data), - to_transaction_id(raw().info), raw().frozen_hash, - get_sync_time()); + return tonlib_api::make_object(std::move(code), std::move(data), raw().frozen_hash); + } + + td::Result> to_raw_fullAccountState() const { + auto state = get_smc_state(); + std::string code; + if (state.code.not_null()) { + code = to_bytes(state.code); + } + std::string data; + if (state.data.not_null()) { + data = to_bytes(state.data); + } + return tonlib_api::make_object( + get_balance(), std::move(code), std::move(data), to_transaction_id(raw().info), to_tonlib_api(raw().block_id), + raw().frozen_hash, get_sync_time()); } td::Result> to_testWallet_accountState() const { @@ -153,8 +219,7 @@ class AccountState { return TonlibError::AccountTypeUnexpected("TestWallet"); } TRY_RESULT(seqno, ton::TestWallet(get_smc_state()).get_seqno()); - return tonlib_api::make_object(get_balance(), static_cast(seqno), - to_transaction_id(raw().info), get_sync_time()); + return tonlib_api::make_object(static_cast(seqno)); } td::Result> to_wallet_accountState() const { @@ -162,8 +227,7 @@ class AccountState { return TonlibError::AccountTypeUnexpected("Wallet"); } TRY_RESULT(seqno, ton::Wallet(get_smc_state()).get_seqno()); - return tonlib_api::make_object(get_balance(), static_cast(seqno), - to_transaction_id(raw().info), get_sync_time()); + return tonlib_api::make_object(static_cast(seqno)); } td::Result> to_wallet_v3_accountState() const { if (wallet_type_ != WalletV3) { @@ -172,9 +236,28 @@ class AccountState { auto wallet = ton::WalletV3(get_smc_state()); TRY_RESULT(seqno, wallet.get_seqno()); TRY_RESULT(wallet_id, wallet.get_wallet_id()); - return tonlib_api::make_object( - get_balance(), static_cast(wallet_id), static_cast(seqno), - to_transaction_id(raw().info), get_sync_time()); + return tonlib_api::make_object(static_cast(wallet_id), + static_cast(seqno)); + } + td::Result> to_wallet_highload_v1_accountState() + const { + if (wallet_type_ != HighloadWalletV1) { + return TonlibError::AccountTypeUnexpected("HighloadWalletV1"); + } + auto wallet = ton::HighloadWallet(get_smc_state()); + TRY_RESULT(seqno, wallet.get_seqno()); + TRY_RESULT(wallet_id, wallet.get_wallet_id()); + return tonlib_api::make_object(static_cast(wallet_id), + static_cast(seqno)); + } + td::Result> to_wallet_highload_v2_accountState() + const { + if (wallet_type_ != HighloadWalletV2) { + return TonlibError::AccountTypeUnexpected("HighloadWalletV2"); + } + auto wallet = ton::HighloadWalletV2(get_smc_state()); + TRY_RESULT(wallet_id, wallet.get_wallet_id()); + return tonlib_api::make_object(static_cast(wallet_id)); } td::Result> to_testGiver_accountState() const { @@ -182,41 +265,106 @@ class AccountState { return TonlibError::AccountTypeUnexpected("TestGiver"); } TRY_RESULT(seqno, ton::TestGiver(get_smc_state()).get_seqno()); - return tonlib_api::make_object(get_balance(), static_cast(seqno), - to_transaction_id(raw().info), get_sync_time()); + return tonlib_api::make_object(static_cast(seqno)); } - td::Result> to_generic_accountState() const { - switch (wallet_type_) { - case Empty: - return tonlib_api::make_object(to_uninited_accountState()); - case Unknown: { - TRY_RESULT(res, to_raw_accountState()); - return tonlib_api::make_object(std::move(res)); - } - case Giver: { - TRY_RESULT(res, to_testGiver_accountState()); - return tonlib_api::make_object(std::move(res)); - } - case SimpleWallet: { - TRY_RESULT(res, to_testWallet_accountState()); - return tonlib_api::make_object(std::move(res)); - } - case Wallet: { - TRY_RESULT(res, to_wallet_accountState()); - return tonlib_api::make_object(std::move(res)); - } - case WalletV3: { - TRY_RESULT(res, to_wallet_v3_accountState()); - return tonlib_api::make_object(std::move(res)); - } + td::Result> to_dns_accountState() const { + if (wallet_type_ != ManualDns) { + return TonlibError::AccountTypeUnexpected("ManualDns"); } - UNREACHABLE(); + TRY_RESULT(wallet_id, ton::ManualDns(get_smc_state()).get_wallet_id()); + return tonlib_api::make_object(static_cast(wallet_id)); } - enum WalletType { Empty, Unknown, Giver, SimpleWallet, Wallet, WalletV3 }; + td::Result> to_accountState() const { + auto f = [](auto&& r_x) -> td::Result> { + TRY_RESULT(x, std::move(r_x)); + return std::move(x); + }; + + switch (wallet_type_) { + case Empty: + return to_uninited_accountState(); + case Unknown: + return f(to_raw_accountState()); + case Giver: + return f(to_testGiver_accountState()); + case SimpleWallet: + return f(to_testWallet_accountState()); + case Wallet: + return f(to_wallet_accountState()); + case WalletV3: + return f(to_wallet_v3_accountState()); + case HighloadWalletV1: + return f(to_wallet_highload_v1_accountState()); + case HighloadWalletV2: + return f(to_wallet_highload_v2_accountState()); + case ManualDns: + return f(to_dns_accountState()); + default: + UNREACHABLE(); + } + } + + td::Result> to_fullAccountState() const { + TRY_RESULT(account_state, to_accountState()); + return tonlib_api::make_object(get_balance(), to_transaction_id(raw().info), + to_tonlib_api(raw().block_id), get_sync_time(), + std::move(account_state)); + } + + enum WalletType { + Empty, + Unknown, + Giver, + SimpleWallet, + Wallet, + WalletV3, + HighloadWalletV1, + HighloadWalletV2, + ManualDns + }; WalletType get_wallet_type() const { return wallet_type_; } + bool is_wallet() const { + switch (get_wallet_type()) { + case AccountState::Empty: + case AccountState::Unknown: + case AccountState::ManualDns: + return false; + case AccountState::Giver: + case AccountState::SimpleWallet: + case AccountState::Wallet: + case AccountState::WalletV3: + case AccountState::HighloadWalletV1: + case AccountState::HighloadWalletV2: + return true; + } + UNREACHABLE(); + return false; + } + td::unique_ptr get_wallet() const { + switch (get_wallet_type()) { + case AccountState::Empty: + case AccountState::Unknown: + case AccountState::ManualDns: + return {}; + case AccountState::Giver: + return td::make_unique(get_smc_state()); + case AccountState::SimpleWallet: + return td::make_unique(get_smc_state()); + case AccountState::Wallet: + return td::make_unique(get_smc_state()); + case AccountState::WalletV3: + return td::make_unique(get_smc_state()); + case AccountState::HighloadWalletV1: + return td::make_unique(get_smc_state()); + case AccountState::HighloadWalletV2: + return td::make_unique(get_smc_state()); + } + UNREACHABLE(); + return {}; + } bool is_frozen() const { return !raw_.frozen_hash.empty(); } @@ -233,6 +381,10 @@ class AccountState { return raw_.info.gen_utime; } + ton::BlockIdExt get_block_id() const { + return raw_.block_id; + } + td::int64 get_balance() const { return raw_.balance; } @@ -245,6 +397,29 @@ class AccountState { if (wallet_type_ != WalletType::Empty) { return wallet_type_; } + auto o_revision = ton::WalletV3::guess_revision(address_, key, wallet_id_); + if (o_revision) { + wallet_type_ = WalletType::WalletV3; + wallet_revision_ = o_revision.value(); + set_new_state({ton::WalletV3::get_init_code(wallet_revision_), ton::WalletV3::get_init_data(key, wallet_id_)}); + return wallet_type_; + } + o_revision = ton::HighloadWalletV2::guess_revision(address_, key, wallet_id_); + if (o_revision) { + wallet_type_ = WalletType::HighloadWalletV2; + wallet_revision_ = o_revision.value(); + set_new_state( + {ton::HighloadWalletV2::get_init_code(wallet_revision_), ton::WalletV3::get_init_data(key, wallet_id_)}); + return wallet_type_; + } + o_revision = ton::ManualDns::guess_revision(address_, key, wallet_id_); + if (o_revision) { + wallet_type_ = WalletType::ManualDns; + wallet_revision_ = o_revision.value(); + auto dns = ton::ManualDns::create(key, wallet_id_, wallet_revision_); + set_new_state(dns->get_state()); + return wallet_type_; + } if (ton::GenericAccount::get_address(address_.workchain, ton::TestWallet::get_init_state(key)).addr == address_.addr) { set_new_state({ton::TestWallet::get_init_code(), ton::TestWallet::get_init_data(key)}); @@ -253,10 +428,11 @@ class AccountState { address_.addr) { set_new_state({ton::Wallet::get_init_code(), ton::Wallet::get_init_data(key)}); wallet_type_ = WalletType::Wallet; - } else if (ton::GenericAccount::get_address(address_.workchain, ton::WalletV3::get_init_state(key, wallet_id_)) + } else if (ton::GenericAccount::get_address(address_.workchain, + ton::HighloadWallet::get_init_state(key, wallet_id_)) .addr == address_.addr) { - set_new_state({ton::WalletV3::get_init_code(), ton::WalletV3::get_init_data(key, wallet_id_)}); - wallet_type_ = WalletType::WalletV3; + set_new_state({ton::HighloadWallet::get_init_code(), ton::HighloadWallet::get_init_data(key, wallet_id_)}); + wallet_type_ = WalletType::HighloadWalletV1; } return wallet_type_; } @@ -296,28 +472,48 @@ class AccountState { block::StdAddress address_; RawAccountState raw_; WalletType wallet_type_{Unknown}; + td::int32 wallet_revision_{0}; td::uint32 wallet_id_{0}; bool has_new_state_{false}; - WalletType guess_type() const { + WalletType guess_type() { if (raw_.code.is_null()) { - return WalletType::Empty; + wallet_type_ = WalletType::Empty; + return wallet_type_; } auto code_hash = raw_.code->get_hash(); + auto o_revision = ton::WalletV3::guess_revision(code_hash); + if (o_revision) { + wallet_type_ = WalletType::WalletV3; + wallet_revision_ = o_revision.value(); + return wallet_type_; + } + o_revision = ton::HighloadWalletV2::guess_revision(code_hash); + if (o_revision) { + wallet_type_ = WalletType::HighloadWalletV2; + wallet_revision_ = o_revision.value(); + return wallet_type_; + } + o_revision = ton::ManualDns::guess_revision(code_hash); + if (o_revision) { + wallet_type_ = WalletType::ManualDns; + wallet_revision_ = o_revision.value(); + return wallet_type_; + } + if (code_hash == ton::TestGiver::get_init_code_hash()) { - return WalletType::Giver; + wallet_type_ = WalletType::Giver; + } else if (code_hash == ton::TestWallet::get_init_code_hash()) { + wallet_type_ = WalletType::SimpleWallet; + } else if (code_hash == ton::Wallet::get_init_code_hash()) { + wallet_type_ = WalletType::Wallet; + } else if (code_hash == ton::HighloadWallet::get_init_code_hash()) { + wallet_type_ = WalletType::HighloadWalletV1; + } else { + LOG(WARNING) << "Unknown code hash: " << td::base64_encode(code_hash.as_slice()); + wallet_type_ = WalletType::Unknown; } - if (code_hash == ton::TestWallet::get_init_code_hash()) { - return WalletType::SimpleWallet; - } - if (code_hash == ton::Wallet::get_init_code_hash()) { - return WalletType::Wallet; - } - if (code_hash == ton::WalletV3::get_init_code_hash()) { - return WalletType::WalletV3; - } - LOG(WARNING) << "Unknown code hash: " << td::base64_encode(code_hash.as_slice()); - return WalletType::Unknown; + return wallet_type_; } }; @@ -325,7 +521,7 @@ class Query { public: struct Raw { td::unique_ptr source; - td::unique_ptr destination; + std::vector> destinations; td::uint32 valid_until{std::numeric_limits::max()}; @@ -419,7 +615,7 @@ class Query { } }; - td::Result calc_fwd_fees(td::Ref list, const block::MsgPrices& msg_prices) { + td::Result calc_fwd_fees(td::Ref list, block::MsgPrices** msg_prices, bool is_masterchain) { td::int64 res = 0; std::vector> actions; int n{0}; @@ -457,10 +653,31 @@ class Query { if (!tlb::type_unpack_cell(act_rec.out_msg, block::gen::t_MessageRelaxed_Any, msg)) { return td::Status::Error("estimate_fee: can't parse send_msg"); } + + bool dest_is_masterchain = false; + if (block::gen::t_CommonMsgInfoRelaxed.get_tag(*msg.info) == block::gen::CommonMsgInfoRelaxed::int_msg_info) { + block::gen::CommonMsgInfoRelaxed::Record_int_msg_info info; + if (!tlb::csr_unpack(msg.info, info)) { + return td::Status::Error("estimate_fee: can't parse send_msg"); + } + auto dest_addr = info.dest; + if (!dest_addr->prefetch_ulong(1)) { + return td::Status::Error("estimate_fee: messages with external addresses are unsupported"); + } + int tag = block::gen::t_MsgAddressInt.get_tag(*dest_addr); + + if (tag == block::gen::MsgAddressInt::addr_std) { + block::gen::MsgAddressInt::Record_addr_std recs; + if (!tlb::csr_unpack(dest_addr, recs)) { + return td::Status::Error("estimate_fee: can't parse send_msg"); + } + dest_is_masterchain = recs.workchain_id == ton::masterchainId; + } + } vm::CellStorageStat sstat; // for message size sstat.add_used_storage(msg.init, true, 3); // message init sstat.add_used_storage(msg.body, true, 3); // message body (the root cell itself is not counted) - res += msg_prices.compute_fwd_fees(sstat.cells, sstat.bits); + res += msg_prices[is_masterchain || dest_is_masterchain]->compute_fwd_fees(sstat.cells, sstat.bits); break; } case block::gen::OutAction::action_reserve_currency: @@ -469,34 +686,26 @@ class Query { } return res; } - td::Result> estimate_fees(bool ignore_chksig, const block::Config& cfg) { + td::Result>> estimate_fees(bool ignore_chksig, const block::Config& cfg) { // gas fees bool is_masterchain = raw_.source->get_address().workchain == ton::masterchainId; - bool dest_is_masterchain = raw_.destination && raw_.destination->get_address().workchain == ton::masterchainId; TRY_RESULT(gas_limits_prices, cfg.get_gas_limits_prices(is_masterchain)); - TRY_RESULT(dest_gas_limits_prices, cfg.get_gas_limits_prices(dest_is_masterchain)); - TRY_RESULT(msg_prices, cfg.get_msg_prices(is_masterchain || dest_is_masterchain)); TRY_RESULT(storage_prices, cfg.get_storage_prices()); - + TRY_RESULT(masterchain_msg_prices, cfg.get_msg_prices(true)); + TRY_RESULT(basechain_msg_prices, cfg.get_msg_prices(false)); + block::MsgPrices* msg_prices[2] = {&basechain_msg_prices, &masterchain_msg_prices}; auto storage_fee_256 = block::StoragePrices::compute_storage_fees( raw_.source->get_sync_time(), storage_prices, raw_.source->raw().storage_stat, raw_.source->raw().storage_last_paid, false, is_masterchain); auto storage_fee = storage_fee_256.is_null() ? 0 : storage_fee_256->to_long(); - auto dest_storage_fee_256 = - raw_.destination ? block::StoragePrices::compute_storage_fees( - raw_.destination->get_sync_time(), storage_prices, raw_.destination->raw().storage_stat, - raw_.destination->raw().storage_last_paid, false, is_masterchain) - : td::make_refint(0); - auto dest_storage_fee = dest_storage_fee_256.is_null() ? 0 : dest_storage_fee_256->to_long(); - auto smc = ton::SmartContract::create(raw_.source->get_smc_state()); td::int64 in_fwd_fee = 0; { vm::CellStorageStat sstat; // for message size sstat.add_used_storage(raw_.message, true, 3); // message init - in_fwd_fee += msg_prices.compute_fwd_fees(sstat.cells, sstat.bits); + in_fwd_fee += msg_prices[is_masterchain]->compute_fwd_fees(sstat.cells, sstat.bits); } vm::GasLimits gas_limits = compute_gas_limits(td::make_refint(raw_.source->get_balance()), gas_limits_prices); @@ -510,7 +719,7 @@ class Query { //int out_act_num = output_actions_count(res.actions); //block::gen::OutList{out_act_num}.print_ref(std::cerr, res.actions); - TRY_RESULT_ASSIGN(fwd_fee, calc_fwd_fees(res.actions, msg_prices)); + TRY_RESULT_ASSIGN(fwd_fee, calc_fwd_fees(res.actions, msg_prices, is_masterchain)); } auto gas_fee = res.accepted ? compute_gas_price(res.gas_used, gas_limits_prices)->to_long() : 0; @@ -522,12 +731,25 @@ class Query { fee.gas_fee = gas_fee; fee.fwd_fee = fwd_fee; - Fee dst_fee; - if (raw_.destination && raw_.destination->get_wallet_type() != AccountState::WalletType::Empty) { - dst_fee.gas_fee = dest_gas_limits_prices.flat_gas_price; - dst_fee.storage_fee = dest_storage_fee; + std::vector dst_fees; + + for (auto& destination : raw_.destinations) { + bool dest_is_masterchain = destination && destination->get_address().workchain == ton::masterchainId; + TRY_RESULT(dest_gas_limits_prices, cfg.get_gas_limits_prices(dest_is_masterchain)); + auto dest_storage_fee_256 = + destination ? block::StoragePrices::compute_storage_fees( + destination->get_sync_time(), storage_prices, destination->raw().storage_stat, + destination->raw().storage_last_paid, false, is_masterchain) + : td::make_refint(0); + Fee dst_fee; + auto dest_storage_fee = dest_storage_fee_256.is_null() ? 0 : dest_storage_fee_256->to_long(); + if (destination && destination->get_wallet_type() != AccountState::WalletType::Empty) { + dst_fee.gas_fee = dest_gas_limits_prices.flat_gas_price; + dst_fee.storage_fee = dest_storage_fee; + } + dst_fees.push_back(dst_fee); } - return std::make_pair(fee, dst_fee); + return std::make_pair(fee, dst_fees); } private: @@ -644,20 +866,136 @@ class GetTransactionHistory : public td::actor::Actor { } }; +class RemoteRunSmcMethod : public td::actor::Actor { + public: + RemoteRunSmcMethod(ExtClientRef ext_client_ref, int_api::RemoteRunSmcMethod query, td::actor::ActorShared<> parent, + td::Promise&& promise) + : query_(std::move(query)), promise_(std::move(promise)), parent_(std::move(parent)) { + client_.set_client(ext_client_ref); + } + + private: + int_api::RemoteRunSmcMethod query_; + td::Promise promise_; + td::actor::ActorShared<> parent_; + ExtClient client_; + + void with_run_method_result( + td::Result> r_run_method_result) { + check(do_with_run_method_result(std::move(r_run_method_result))); + } + + td::Status do_with_run_method_result( + td::Result> r_run_method_result) { + TRY_RESULT(run_method_result, std::move(r_run_method_result)); + TRY_RESULT_PREFIX(state, TRY_VM(do_with_run_method_result(std::move(run_method_result))), + TonlibError::ValidateAccountState()); + promise_.set_value(std::move(state)); + stop(); + return td::Status::OK(); + } + td::Result do_with_run_method_result( + ton::tl_object_ptr run_method_result) { + auto account_state = create_account_state(run_method_result); + TRY_RESULT(info, account_state.validate(query_.block_id.value(), query_.address)); + auto serialized_state = account_state.state.clone(); + int_api::RemoteRunSmcMethod::ReturnType res; + res.block_id = query_.block_id.value(); + auto cell = info.root; + if (cell.is_null()) { + return res; + } + block::gen::Account::Record_account account; + if (!tlb::unpack_cell(cell, account)) { + return td::Status::Error("Failed to unpack Account"); + } + + block::gen::AccountStorage::Record storage; + if (!tlb::csr_unpack(account.storage, storage)) { + return td::Status::Error("Failed to unpack AccountStorage"); + } + auto state_tag = block::gen::t_AccountState.get_tag(*storage.state); + if (state_tag < 0) { + return td::Status::Error("Failed to parse AccountState tag"); + } + if (state_tag != block::gen::AccountState::account_active) { + return td::Status::Error("Account is not active"); + } + block::gen::AccountState::Record_account_active state; + if (!tlb::csr_unpack(storage.state, state)) { + return td::Status::Error("Failed to parse AccountState"); + } + block::gen::StateInit::Record state_init; + if (!tlb::csr_unpack(state.x, state_init)) { + return td::Status::Error("Failed to parse StateInit"); + } + state_init.code->prefetch_maybe_ref(res.smc_state.code); + state_init.data->prefetch_maybe_ref(res.smc_state.data); + return res; + } + + void with_last_block(td::Result r_last_block) { + check(do_with_last_block(std::move(r_last_block))); + } + + td::Status with_block_id() { + TRY_RESULT(method_id, query_.args.get_method_id()); + TRY_RESULT(serialized_stack, query_.args.get_serialized_stack()); + client_.send_query( + //liteServer.runSmcMethod mode:# id:tonNode.blockIdExt account:liteServer.accountId method_id:long params:bytes = liteServer.RunMethodResult; + ton::lite_api::liteServer_runSmcMethod( + 0x1f, ton::create_tl_lite_block_id(query_.block_id.value()), + ton::create_tl_object(query_.address.workchain, query_.address.addr), + method_id, std::move(serialized_stack)), + [self = this](auto r_state) { self->with_run_method_result(std::move(r_state)); }, + query_.block_id.value().id.seqno); + return td::Status::OK(); + } + + td::Status do_with_last_block(td::Result r_last_block) { + TRY_RESULT(last_block, std::move(r_last_block)); + query_.block_id = std::move(last_block.last_block_id); + with_block_id(); + return td::Status::OK(); + } + + void start_up() override { + if (query_.block_id) { + check(with_block_id()); + } else { + client_.with_last_block( + [self = this](td::Result r_last_block) { self->with_last_block(std::move(r_last_block)); }); + } + } + + void check(td::Status status) { + if (status.is_error()) { + promise_.set_error(std::move(status)); + stop(); + } + } + void hangup() override { + check(TonlibError::Cancelled()); + } +}; + class GetRawAccountState : public td::actor::Actor { public: - GetRawAccountState(ExtClientRef ext_client_ref, block::StdAddress address, td::actor::ActorShared<> parent, - td::Promise&& promise) - : address_(std::move(address)), promise_(std::move(promise)), parent_(std::move(parent)) { + GetRawAccountState(ExtClientRef ext_client_ref, block::StdAddress address, td::optional block_id, + td::actor::ActorShared<> parent, td::Promise&& promise) + : address_(std::move(address)) + , block_id_(std::move(block_id)) + , promise_(std::move(promise)) + , parent_(std::move(parent)) { client_.set_client(ext_client_ref); } private: block::StdAddress address_; + td::optional block_id_; td::Promise promise_; td::actor::ActorShared<> parent_; ExtClient client_; - LastBlockState last_block_; void with_account_state(td::Result> r_account_state) { check(do_with_account_state(std::move(r_account_state))); @@ -676,14 +1014,14 @@ class GetRawAccountState : public td::actor::Actor { td::Result do_with_account_state( ton::tl_object_ptr raw_account_state) { auto account_state = create_account_state(std::move(raw_account_state)); - TRY_RESULT(info, account_state.validate(last_block_.last_block_id, address_)); + TRY_RESULT(info, account_state.validate(block_id_.value(), address_)); auto serialized_state = account_state.state.clone(); RawAccountState res; + res.block_id = block_id_.value(); res.info = std::move(info); - LOG_IF(ERROR, res.info.gen_utime > last_block_.utime) << res.info.gen_utime << " " << last_block_.utime; auto cell = res.info.root; - std::ostringstream outp; - block::gen::t_Account.print_ref(outp, cell); + //std::ostringstream outp; + //block::gen::t_Account.print_ref(outp, cell); //LOG(INFO) << outp.str(); if (cell.is_null()) { return res; @@ -766,20 +1104,28 @@ class GetRawAccountState : public td::actor::Actor { check(do_with_last_block(std::move(r_last_block))); } - td::Status do_with_last_block(td::Result r_last_block) { - TRY_RESULT_ASSIGN(last_block_, std::move(r_last_block)); + void with_block_id() { client_.send_query( ton::lite_api::liteServer_getAccountState( - ton::create_tl_lite_block_id(last_block_.last_block_id), + ton::create_tl_lite_block_id(block_id_.value()), ton::create_tl_object(address_.workchain, address_.addr)), - [self = this](auto r_state) { self->with_account_state(std::move(r_state)); }, - last_block_.last_block_id.id.seqno); + [self = this](auto r_state) { self->with_account_state(std::move(r_state)); }, block_id_.value().id.seqno); + } + + td::Status do_with_last_block(td::Result r_last_block) { + TRY_RESULT(last_block, std::move(r_last_block)); + block_id_ = std::move(last_block.last_block_id); + with_block_id(); return td::Status::OK(); } void start_up() override { - client_.with_last_block( - [self = this](td::Result r_last_block) { self->with_last_block(std::move(r_last_block)); }); + if (block_id_) { + with_block_id(); + } else { + client_.with_last_block( + [self = this](td::Result r_last_block) { self->with_last_block(std::move(r_last_block)); }); + } } void check(td::Status status) { @@ -867,7 +1213,7 @@ void TonlibClient::update_last_block_state(LastBlockState state, td::uint32 conf return; } - last_block_storage_.save_state(blockchain_name_, state); + last_block_storage_.save_state(last_state_key_, state); } void TonlibClient::update_sync_state(LastBlockSyncState state, td::uint32 config_generation) { @@ -889,7 +1235,7 @@ void TonlibClient::update_sync_state(LastBlockSyncState state, td::uint32 config } } -void TonlibClient::init_last_block(td::optional o_master_config) { +void TonlibClient::init_last_block(LastBlockState state) { ref_cnt_++; class Callback : public LastBlock::Callback { public: @@ -907,31 +1253,8 @@ void TonlibClient::init_last_block(td::optional o_master_config) { td::actor::ActorShared client_; td::uint32 config_generation_; }; - LastBlockState state; - td::Result r_state; - if (!ignore_cache_) { - r_state = last_block_storage_.get_state(blockchain_name_); - } - if (ignore_cache_ || r_state.is_error()) { - LOG_IF(WARNING, !ignore_cache_) << "Unknown LastBlockState: " << r_state.error(); - state.zero_state_id = ton::ZeroStateIdExt(config_.zero_state_id.id.workchain, config_.zero_state_id.root_hash, - config_.zero_state_id.file_hash), - state.last_block_id = config_.zero_state_id; - state.last_key_block_id = config_.zero_state_id; - last_block_storage_.save_state(blockchain_name_, state); - } else { - state = r_state.move_as_ok(); - } - - if (o_master_config) { - auto master_config = o_master_config.unwrap(); - if (master_config.init_block_id.is_valid() && - state.last_key_block_id.id.seqno < master_config.init_block_id.id.seqno) { - state.last_key_block_id = master_config.init_block_id; - LOG(INFO) << "Use init block from MASTER config: " << master_config.init_block_id.to_str(); - } - } + last_block_storage_.save_state(last_state_key_, state); raw_last_block_ = td::actor::create_actor( td::actor::ActorOptions().with_name("LastBlock").with_poll(false), get_client_ref(), std::move(state), config_, @@ -965,6 +1288,16 @@ void TonlibClient::on_update(object_ptr response) { on_result(0, std::move(response)); } +void TonlibClient::make_any_request(tonlib_api::Function& function, QueryContext query_context, + td::Promise>&& promise) { + auto old_context = std::move(query_context_); + SCOPE_EXIT { + query_context_ = std::move(old_context); + }; + query_context_ = std::move(query_context); + downcast_call(function, [&](auto& request) { this->make_request(request, promise.wrap([](auto x) { return x; })); }); +} + void TonlibClient::request(td::uint64 id, tonlib_api::object_ptr function) { VLOG(tonlib_query) << "Tonlib got query " << td::tag("id", id) << " " << to_string(function); if (function == nullptr) { @@ -985,22 +1318,20 @@ void TonlibClient::request(td::uint64 id, tonlib_api::object_ptr::ReturnType; - ref_cnt_++; - td::Promise promise = [actor_id = actor_id(self), id, - tmp = actor_shared(self)](td::Result r_result) { - tonlib_api::object_ptr result; - if (r_result.is_error()) { - result = status_to_tonlib_api(r_result.error()); - } else { - result = r_result.move_as_ok(); - } + ref_cnt_++; + using Object = tonlib_api::object_ptr; + td::Promise promise = [actor_id = actor_id(this), id, tmp = actor_shared(this)](td::Result r_result) { + tonlib_api::object_ptr result; + if (r_result.is_error()) { + result = status_to_tonlib_api(r_result.error()); + } else { + result = r_result.move_as_ok(); + } - send_closure(actor_id, &TonlibClient::on_result, id, std::move(result)); - }; - this->make_request(request, std::move(promise)); - }); + send_closure(actor_id, &TonlibClient::on_result, id, std::move(result)); + }; + + make_any_request(*function, {}, std::move(promise)); } void TonlibClient::close() { stop(); @@ -1013,8 +1344,8 @@ tonlib_api::object_ptr TonlibClient::static_request( return tonlib_api::make_object(400, "Request is empty"); } - tonlib_api::object_ptr response; - downcast_call(*function, [&response](auto& request) { response = TonlibClient::do_static_request(request); }); + auto response = downcast_call2>( + *function, [](auto& request) { return TonlibClient::do_static_request(request); }); VLOG(tonlib_query) << " answer static query " << to_string(response); return response; } @@ -1022,14 +1353,9 @@ tonlib_api::object_ptr TonlibClient::static_request( bool TonlibClient::is_static_request(td::int32 id) { switch (id) { case tonlib_api::runTests::ID: - case tonlib_api::raw_getAccountAddress::ID: - case tonlib_api::testWallet_getAccountAddress::ID: - case tonlib_api::wallet_getAccountAddress::ID: - case tonlib_api::wallet_v3_getAccountAddress::ID: - case tonlib_api::testGiver_getAccountAddress::ID: + case tonlib_api::getAccountAddress::ID: case tonlib_api::packAccountAddress::ID: case tonlib_api::unpackAccountAddress::ID: - case tonlib_api::options_validateConfig::ID: case tonlib_api::getBip39Hints::ID: case tonlib_api::setLogStream::ID: case tonlib_api::getLogStream::ID: @@ -1071,29 +1397,63 @@ td::Result get_public_key(td::Slice public_key) { return address; } -td::Result get_account_address(const tonlib_api::raw_initialAccountState& raw_state) { +td::Result get_account_address(const tonlib_api::raw_initialAccountState& raw_state, + td::int32 revision) { TRY_RESULT_PREFIX(code, vm::std_boc_deserialize(raw_state.code_), TonlibError::InvalidBagOfCells("raw_state.code")); TRY_RESULT_PREFIX(data, vm::std_boc_deserialize(raw_state.data_), TonlibError::InvalidBagOfCells("raw_state.data")); return ton::GenericAccount::get_address(0 /*zerochain*/, ton::GenericAccount::get_init_state(std::move(code), std::move(data))); } -td::Result get_account_address(const tonlib_api::testWallet_initialAccountState& test_wallet_state) { - TRY_RESULT(key_bytes, get_public_key(test_wallet_state.public_key_)); - auto key = td::Ed25519::PublicKey(td::SecureString(key_bytes.key)); - return ton::GenericAccount::get_address(0 /*zerochain*/, ton::TestWallet::get_init_state(key)); +td::Result get_account_address(const tonlib_api::testGiver_initialAccountState& test_wallet_state, + td::int32 revision) { + return ton::TestGiver::address(); } -td::Result get_account_address(const tonlib_api::wallet_initialAccountState& test_wallet_state) { +td::Result get_account_address(const tonlib_api::testWallet_initialAccountState& test_wallet_state, + td::int32 revision) { TRY_RESULT(key_bytes, get_public_key(test_wallet_state.public_key_)); auto key = td::Ed25519::PublicKey(td::SecureString(key_bytes.key)); - return ton::GenericAccount::get_address(0 /*zerochain*/, ton::Wallet::get_init_state(key)); + return ton::GenericAccount::get_address(0 /*zerochain*/, ton::TestWallet::get_init_state(key, revision)); } -td::Result get_account_address(const tonlib_api::wallet_v3_initialAccountState& test_wallet_state) { + +td::Result get_account_address(const tonlib_api::wallet_initialAccountState& wallet_state, + td::int32 revision) { + TRY_RESULT(key_bytes, get_public_key(wallet_state.public_key_)); + auto key = td::Ed25519::PublicKey(td::SecureString(key_bytes.key)); + return ton::GenericAccount::get_address(0 /*zerochain*/, ton::Wallet::get_init_state(key, revision)); +} +td::Result get_account_address(const tonlib_api::wallet_v3_initialAccountState& test_wallet_state, + td::int32 revision) { TRY_RESULT(key_bytes, get_public_key(test_wallet_state.public_key_)); auto key = td::Ed25519::PublicKey(td::SecureString(key_bytes.key)); return ton::GenericAccount::get_address( - 0 /*zerochain*/, ton::WalletV3::get_init_state(key, static_cast(test_wallet_state.wallet_id_))); + 0 /*zerochain*/, + ton::WalletV3::get_init_state(key, static_cast(test_wallet_state.wallet_id_), revision)); +} + +td::Result get_account_address( + const tonlib_api::wallet_highload_v1_initialAccountState& test_wallet_state, td::int32 revision) { + TRY_RESULT(key_bytes, get_public_key(test_wallet_state.public_key_)); + auto key = td::Ed25519::PublicKey(td::SecureString(key_bytes.key)); + return ton::GenericAccount::get_address( + 0 /*zerochain*/, ton::HighloadWallet::get_init_state(key, static_cast(test_wallet_state.wallet_id_))); +} + +td::Result get_account_address( + const tonlib_api::wallet_highload_v2_initialAccountState& test_wallet_state, td::int32 revision) { + TRY_RESULT(key_bytes, get_public_key(test_wallet_state.public_key_)); + auto key = td::Ed25519::PublicKey(td::SecureString(key_bytes.key)); + return ton::GenericAccount::get_address( + 0 /*zerochain*/, + ton::HighloadWalletV2::get_init_state(key, static_cast(test_wallet_state.wallet_id_), revision)); +} + +td::Result get_account_address(const tonlib_api::dns_initialAccountState& dns_state, + td::int32 revision) { + TRY_RESULT(key_bytes, get_public_key(dns_state.public_key_)); + auto key = td::Ed25519::PublicKey(td::SecureString(key_bytes.key)); + return ton::ManualDns::create(key, static_cast(dns_state.wallet_id_), revision)->get_address(); } td::Result get_account_address(td::Slice account_address) { @@ -1101,59 +1461,115 @@ td::Result get_account_address(td::Slice account_address) { return address; } +td::Result get_adnl_address(td::Slice adnl_address) { + TRY_RESULT_PREFIX(address, td::adnl_id_decode(adnl_address), + TonlibError::InvalidField("adnl_address", "can't decode")); + return address; +} + +static td::optional get_wallet_type(tonlib_api::InitialAccountState& state) { + return downcast_call2>( + state, + td::overloaded( + [](const tonlib_api::raw_initialAccountState&) { return td::optional(); }, + [](const tonlib_api::testGiver_initialAccountState&) { return td::optional(); }, + [](const tonlib_api::testWallet_initialAccountState&) { return ton::SmartContractCode::WalletV1; }, + [](const tonlib_api::wallet_initialAccountState&) { return ton::SmartContractCode::WalletV2; }, + [](const tonlib_api::wallet_v3_initialAccountState&) { return ton::SmartContractCode::WalletV3; }, + [](const tonlib_api::wallet_highload_v1_initialAccountState&) { + return ton::SmartContractCode::HighloadWalletV1; + }, + [](const tonlib_api::wallet_highload_v2_initialAccountState&) { + return ton::SmartContractCode::HighloadWalletV2; + }, + [](const tonlib_api::dns_initialAccountState&) { return ton::SmartContractCode::ManualDns; })); +} + tonlib_api::object_ptr TonlibClient::do_static_request( - const tonlib_api::raw_getAccountAddress& request) { - if (!request.initital_account_state_) { + const tonlib_api::getAccountAddress& request) { + if (!request.initial_account_state_) { return status_to_tonlib_api(TonlibError::EmptyField("initial_account_state")); } - auto r_account_address = get_account_address(*request.initital_account_state_); + auto o_type = get_wallet_type(*request.initial_account_state_); + if (o_type) { + auto status = ton::SmartContractCode::validate_revision(o_type.value(), request.revision_); + if (status.is_error()) { + return status_to_tonlib_api(TonlibError::InvalidRevision()); + } + } + auto r_account_address = downcast_call2>( + *request.initial_account_state_, + [&request](auto&& state) { return get_account_address(state, request.revision_); }); if (r_account_address.is_error()) { return status_to_tonlib_api(r_account_address.error()); } return tonlib_api::make_object(r_account_address.ok().rserialize(true)); } -tonlib_api::object_ptr TonlibClient::do_static_request( - const tonlib_api::testWallet_getAccountAddress& request) { - if (!request.initital_account_state_) { - return status_to_tonlib_api(TonlibError::EmptyField("initial_account_state")); +td::Status TonlibClient::do_request(const tonlib_api::guessAccountRevision& request, + td::Promise>&& promise) { + if (!request.initial_account_state_) { + return TonlibError::EmptyField("initial_account_state"); } - if (!request.initital_account_state_) { - return status_to_tonlib_api(TonlibError::EmptyField("initial_account_state")); + auto o_type = get_wallet_type(*request.initial_account_state_); + if (!o_type) { + promise.set_value(tonlib_api::make_object(std::vector{0})); + return td::Status::OK(); } - auto r_account_address = get_account_address(*request.initital_account_state_); - if (r_account_address.is_error()) { - return status_to_tonlib_api(r_account_address.error()); - } - return tonlib_api::make_object(r_account_address.ok().rserialize(true)); -} + auto revisions = ton::SmartContractCode::get_revisions(o_type.value()); -tonlib_api::object_ptr TonlibClient::do_static_request( - const tonlib_api::wallet_getAccountAddress& request) { - if (!request.initital_account_state_) { - return status_to_tonlib_api(TonlibError::EmptyField("initial_account_state")); - } - auto r_account_address = get_account_address(*request.initital_account_state_); - if (r_account_address.is_error()) { - return status_to_tonlib_api(r_account_address.error()); - } - return tonlib_api::make_object(r_account_address.ok().rserialize(true)); -} -tonlib_api::object_ptr TonlibClient::do_static_request( - const tonlib_api::wallet_v3_getAccountAddress& request) { - if (!request.initital_account_state_) { - return status_to_tonlib_api(TonlibError::EmptyField("initial_account_state")); - } - auto r_account_address = get_account_address(*request.initital_account_state_); - if (r_account_address.is_error()) { - return status_to_tonlib_api(r_account_address.error()); - } - return tonlib_api::make_object(r_account_address.ok().rserialize(true)); -} + std::vector> addresses; + TRY_STATUS(downcast_call2(*request.initial_account_state_, [&revisions, &addresses](const auto& state) { + for (auto revision : revisions) { + TRY_RESULT(address, get_account_address(state, revision)); + addresses.push_back(std::make_pair(revision, address)); + } + return td::Status::OK(); + })); -tonlib_api::object_ptr TonlibClient::do_static_request( - const tonlib_api::testGiver_getAccountAddress& request) { - return tonlib_api::make_object(ton::TestGiver::address().rserialize(true)); + auto actor_id = actor_id_++; + class GuessRevisions : public TonlibQueryActor { + public: + GuessRevisions(td::actor::ActorShared client, td::optional block_id, + std::vector> addresses, td::Promise> promise) + : TonlibQueryActor(std::move(client)) + , block_id_(std::move(block_id)) + , addresses_(std::move(addresses)) + , promise_(std::move(promise)) { + } + + private: + td::optional block_id_; + std::vector> addresses_; + td::Promise> promise_; + + size_t left_{0}; + std::vector res; + + void start_up() { + left_ += addresses_.size(); + for (auto& p : addresses_) { + send_query(int_api::GetAccountState{p.second, block_id_.copy()}, + promise_send_closure(td::actor::actor_id(this), &GuessRevisions::on_account_state, p.first)); + } + } + void on_account_state(int revision, td::Result> r_state) { + if (r_state.is_ok() && r_state.ok()->get_wallet_type() != AccountState::WalletType::Empty) { + res.push_back(revision); + } + left_--; + if (left_ == 0) { + promise_.set_value(std::move(res)); + stop(); + } + } + }; + + actors_[actor_id] = td::actor::create_actor( + "GuessRevisions", actor_shared(this, actor_id), query_context_.block_id.copy(), std::move(addresses), + promise.wrap( + [](auto&& x) mutable { return tonlib_api::make_object(std::move(x)); })); + return td::Status::OK(); } tonlib_api::object_ptr TonlibClient::do_static_request( @@ -1190,7 +1606,7 @@ tonlib_api::object_ptr TonlibClient::do_static_request(tonli } td::Status TonlibClient::do_request(const tonlib_api::init& request, - td::Promise>&& promise) { + td::Promise>&& promise) { if (state_ != State::Uninited) { return td::Status::Error(400, "Tonlib is already inited"); } @@ -1201,23 +1617,24 @@ td::Status TonlibClient::do_request(const tonlib_api::init& request, return TonlibError::EmptyField("options.keystore_type"); } - td::Result> r_kv; - downcast_call( + auto r_kv = downcast_call2>>( *request.options_->keystore_type_, td::overloaded( - [&](tonlib_api::keyStoreTypeDirectory& directory) { r_kv = KeyValue::create_dir(directory.directory_); }, - [&](tonlib_api::keyStoreTypeInMemory& inmemory) { r_kv = KeyValue::create_inmemory(); })); + [](tonlib_api::keyStoreTypeDirectory& directory) { return KeyValue::create_dir(directory.directory_); }, + [](tonlib_api::keyStoreTypeInMemory& inmemory) { return KeyValue::create_inmemory(); })); TRY_RESULT(kv, std::move(r_kv)); kv_ = std::shared_ptr(kv.release()); key_storage_.set_key_value(kv_); last_block_storage_.set_key_value(kv_); + auto res = tonlib_api::make_object(); if (request.options_->config_) { TRY_RESULT(full_config, validate_config(std::move(request.options_->config_))); + res->config_info_ = to_tonlib_api(full_config); set_config(std::move(full_config)); } state_ = State::Running; - promise.set_value(tonlib_api::make_object()); + promise.set_value(std::move(res)); return td::Status::OK(); } @@ -1291,21 +1708,55 @@ td::Result TonlibClient::validate_config(tonlib_api::o } td::optional o_master_config; + std::string last_state_key; if (config->blockchain_name_.empty()) { + last_state_key = new_config.zero_state_id.root_hash.as_slice().str(); o_master_config = get_default_master_config().by_root_hash(new_config.zero_state_id.root_hash); } else { + last_state_key = config->blockchain_name_; o_master_config = get_default_master_config().by_name(config->blockchain_name_); } if (o_master_config && o_master_config.value().zero_state_id != new_config.zero_state_id) { return TonlibError::InvalidConfig("zero_state differs from embedded zero_state"); } + + LastBlockState state; + td::Result r_state; + if (!config->ignore_cache_) { + r_state = last_block_storage_.get_state(last_state_key); + } + auto zero_state = ton::ZeroStateIdExt(new_config.zero_state_id.id.workchain, new_config.zero_state_id.root_hash, + new_config.zero_state_id.file_hash); + if (config->ignore_cache_ || r_state.is_error()) { + LOG_IF(WARNING, !config->ignore_cache_) << "Unknown LastBlockState: " << r_state.error(); + state.zero_state_id = zero_state; + state.last_block_id = new_config.zero_state_id; + state.last_key_block_id = new_config.zero_state_id; + } else { + state = r_state.move_as_ok(); + if (state.zero_state_id != zero_state) { + LOG(ERROR) << state.zero_state_id.to_str() << " " << zero_state.to_str(); + return TonlibError::InvalidConfig("zero_state differs from cached zero_state"); + } + } + + if (o_master_config) { + auto master_config = o_master_config.unwrap(); + if (master_config.init_block_id.is_valid() && + state.last_key_block_id.id.seqno < master_config.init_block_id.id.seqno) { + state.last_key_block_id = master_config.init_block_id; + LOG(INFO) << "Use init block from MASTER config: " << master_config.init_block_id.to_str(); + } + } + FullConfig res; res.config = std::move(new_config); - res.o_master_config = std::move(o_master_config); - res.ignore_cache = config->ignore_cache_; res.use_callbacks_for_network = config->use_callbacks_for_network_; res.wallet_id = td::as(res.config.zero_state_id.root_hash.as_slice().data()); + res.last_state_key = std::move(last_state_key); + res.last_state = std::move(state); + return std::move(res); } @@ -1313,12 +1764,11 @@ void TonlibClient::set_config(FullConfig full_config) { config_ = std::move(full_config.config); config_generation_++; wallet_id_ = full_config.wallet_id; - blockchain_name_ = config_.zero_state_id.root_hash.as_slice().str(); + last_state_key_ = full_config.last_state_key; use_callbacks_for_network_ = full_config.use_callbacks_for_network; - ignore_cache_ = full_config.ignore_cache; init_ext_client(); - init_last_block(std::move(full_config.o_master_config)); + init_last_block(std::move(full_config.last_state)); init_last_config(); client_.set_client(get_client_ref()); } @@ -1332,23 +1782,23 @@ td::Status TonlibClient::do_request(const tonlib_api::close& request, return td::Status::OK(); } -tonlib_api::object_ptr TonlibClient::do_static_request( - tonlib_api::options_validateConfig& request) { - auto r_config = validate_config(std::move(request.config_)); - if (r_config.is_error()) { - return status_to_tonlib_api(r_config.move_as_error()); - } - return tonlib_api::make_object(r_config.ok().wallet_id); +td::Status TonlibClient::do_request(tonlib_api::options_validateConfig& request, + td::Promise>&& promise) { + TRY_RESULT(config, validate_config(std::move(request.config_))); + auto res = to_tonlib_api(config); + promise.set_value(std::move(res)); + return td::Status::OK(); } td::Status TonlibClient::do_request(tonlib_api::options_setConfig& request, - td::Promise>&& promise) { + td::Promise>&& promise) { if (!request.config_) { return TonlibError::EmptyField("config"); } TRY_RESULT(config, validate_config(std::move(request.config_))); + auto res = to_tonlib_api(config); set_config(std::move(config)); - promise.set_value(tonlib_api::make_object()); + promise.set_value(std::move(res)); return td::Status::OK(); } @@ -1370,158 +1820,185 @@ td::Result to_std_address_or_throw(td::Ref cs) { td::Result to_std_address(td::Ref cs) { return TRY_VM(to_std_address_or_throw(std::move(cs))); } - -td::Result> to_raw_message_or_throw(td::Ref cell) { - block::gen::Message::Record message; - if (!tlb::type_unpack_cell(cell, block::gen::t_Message_Any, message)) { - return td::Status::Error("Failed to unpack Message"); +struct ToRawTransactions { + explicit ToRawTransactions(td::optional private_key) : private_key_(std::move(private_key)) { } - auto tag = block::gen::CommonMsgInfo().get_tag(*message.info); - if (tag < 0) { - return td::Status::Error("Failed to read CommonMsgInfo tag"); - } - switch (tag) { - case block::gen::CommonMsgInfo::int_msg_info: { - block::gen::CommonMsgInfo::Record_int_msg_info msg_info; - if (!tlb::csr_unpack(message.info, msg_info)) { - return td::Status::Error("Failed to unpack CommonMsgInfo::int_msg_info"); - } + td::optional private_key_; + td::Result> to_raw_message_or_throw(td::Ref cell) { + block::gen::Message::Record message; + if (!tlb::type_unpack_cell(cell, block::gen::t_Message_Any, message)) { + return td::Status::Error("Failed to unpack Message"); + } - TRY_RESULT(balance, to_balance(msg_info.value)); - TRY_RESULT(src, to_std_address(msg_info.src)); - TRY_RESULT(dest, to_std_address(msg_info.dest)); - TRY_RESULT(fwd_fee, to_balance(msg_info.fwd_fee)); - TRY_RESULT(ihr_fee, to_balance(msg_info.ihr_fee)); - auto created_lt = static_cast(msg_info.created_lt); - td::Ref body; - if (message.body->prefetch_long(1) == 0) { - body = std::move(message.body); - body.write().advance(1); - } else { - body = vm::load_cell_slice_ref(message.body->prefetch_ref()); - } - auto body_hash = vm::CellBuilder().append_cellslice(*body).finalize()->get_hash().as_slice().str(); - std::string body_message; - if (body->size() >= 32 && body->prefetch_long(32) == 0) { - body.write().fetch_long(32); - auto r_body_message = vm::CellString::load(body.write()); - if (r_body_message.is_ok()) { - body_message = r_body_message.move_as_ok(); + td::Ref body; + if (message.body->prefetch_long(1) == 0) { + body = std::move(message.body); + body.write().advance(1); + } else { + body = vm::load_cell_slice_ref(message.body->prefetch_ref()); + } + auto body_cell = vm::CellBuilder().append_cellslice(*body).finalize(); + auto body_hash = body_cell->get_hash().as_slice().str(); + + tonlib_api::object_ptr data; + if (body->size() >= 32 && static_cast(body->prefetch_long(32)) <= 1) { + auto type = body.write().fetch_long(32); + td::Status status; + + auto r_body_message = vm::CellString::load(body.write()); + LOG_IF(WARNING, r_body_message.is_error()) << "Failed to parse a message: " << r_body_message.error(); + + if (r_body_message.is_ok()) { + if (type == 0) { + LOG(ERROR) << "OK " << r_body_message.ok(); + data = tonlib_api::make_object(r_body_message.move_as_ok()); + } else { + LOG(ERROR) << "TRY DECRYPT"; + auto encrypted_message = r_body_message.move_as_ok(); + auto r_decrypted_message = [&]() -> td::Result { + if (!private_key_) { + return TonlibError::EmptyField("private_key"); + } + TRY_RESULT(decrypted, SimpleEncryptionV2::decrypt_data(encrypted_message, private_key_.value())); + return decrypted.as_slice().str(); + }(); + if (r_decrypted_message.is_ok()) { + data = tonlib_api::make_object(r_decrypted_message.move_as_ok()); + } else { + data = tonlib_api::make_object(encrypted_message); + } } } - - return tonlib_api::make_object(std::move(src), std::move(dest), balance, fwd_fee, - ihr_fee, created_lt, std::move(body_hash), - std::move(body_message)); } - case block::gen::CommonMsgInfo::ext_in_msg_info: { - block::gen::CommonMsgInfo::Record_ext_in_msg_info msg_info; - if (!tlb::csr_unpack(message.info, msg_info)) { - return td::Status::Error("Failed to unpack CommonMsgInfo::ext_in_msg_info"); + if (!data) { + data = tonlib_api::make_object(to_bytes(std::move(body_cell))); + } + + auto tag = block::gen::CommonMsgInfo().get_tag(*message.info); + if (tag < 0) { + return td::Status::Error("Failed to read CommonMsgInfo tag"); + } + switch (tag) { + case block::gen::CommonMsgInfo::int_msg_info: { + block::gen::CommonMsgInfo::Record_int_msg_info msg_info; + if (!tlb::csr_unpack(message.info, msg_info)) { + return td::Status::Error("Failed to unpack CommonMsgInfo::int_msg_info"); + } + + TRY_RESULT(balance, to_balance(msg_info.value)); + TRY_RESULT(src, to_std_address(msg_info.src)); + TRY_RESULT(dest, to_std_address(msg_info.dest)); + TRY_RESULT(fwd_fee, to_balance(msg_info.fwd_fee)); + TRY_RESULT(ihr_fee, to_balance(msg_info.ihr_fee)); + auto created_lt = static_cast(msg_info.created_lt); + + return tonlib_api::make_object(std::move(src), std::move(dest), balance, fwd_fee, + ihr_fee, created_lt, std::move(body_hash), + std::move(data)); } - TRY_RESULT(dest, to_std_address(msg_info.dest)); - td::Ref body; - if (message.body->prefetch_long(1) == 0) { - body = std::move(message.body); - body.write().advance(1); - } else { - body = vm::load_cell_slice_ref(message.body->prefetch_ref()); + case block::gen::CommonMsgInfo::ext_in_msg_info: { + block::gen::CommonMsgInfo::Record_ext_in_msg_info msg_info; + if (!tlb::csr_unpack(message.info, msg_info)) { + return td::Status::Error("Failed to unpack CommonMsgInfo::ext_in_msg_info"); + } + TRY_RESULT(dest, to_std_address(msg_info.dest)); + return tonlib_api::make_object("", std::move(dest), 0, 0, 0, 0, std::move(body_hash), + std::move(data)); } - auto body_hash = vm::CellBuilder().append_cellslice(*body).finalize()->get_hash().as_slice().str(); - return tonlib_api::make_object("", std::move(dest), 0, 0, 0, 0, std::move(body_hash), - ""); - } - case block::gen::CommonMsgInfo::ext_out_msg_info: { - block::gen::CommonMsgInfo::Record_ext_out_msg_info msg_info; - if (!tlb::csr_unpack(message.info, msg_info)) { - return td::Status::Error("Failed to unpack CommonMsgInfo::ext_out_msg_info"); - } - TRY_RESULT(src, to_std_address(msg_info.src)); - return tonlib_api::make_object(std::move(src), "", 0, 0, 0, 0, "", ""); - } - } - - return td::Status::Error("Unknown CommonMsgInfo tag"); -} - -td::Result> to_raw_message(td::Ref cell) { - return TRY_VM(to_raw_message_or_throw(std::move(cell))); -} - -td::Result> to_raw_transaction_or_throw( - block::Transaction::Info&& info) { - std::string data; - - tonlib_api::object_ptr in_msg; - std::vector> out_msgs; - td::int64 fees = 0; - td::int64 storage_fee = 0; - if (info.transaction.not_null()) { - data = to_bytes(info.transaction); - block::gen::Transaction::Record trans; - if (!tlb::unpack_cell(info.transaction, trans)) { - return td::Status::Error("Failed to unpack Transaction"); - } - - TRY_RESULT_ASSIGN(fees, to_balance(trans.total_fees)); - - //std::ostringstream outp; - //block::gen::t_Transaction.print_ref(outp, info.transaction); - //LOG(INFO) << outp.str(); - - auto is_just = trans.r1.in_msg->prefetch_long(1); - if (is_just == trans.r1.in_msg->fetch_long_eof) { - return td::Status::Error("Failed to parse long"); - } - if (is_just == -1) { - auto msg = trans.r1.in_msg->prefetch_ref(); - TRY_RESULT(in_msg_copy, to_raw_message(trans.r1.in_msg->prefetch_ref())); - in_msg = std::move(in_msg_copy); - } - - if (trans.outmsg_cnt != 0) { - vm::Dictionary dict{trans.r1.out_msgs, 15}; - for (int x = 0; x < trans.outmsg_cnt && x < 100; x++) { - TRY_RESULT(out_msg, to_raw_message(dict.lookup_ref(td::BitArray<15>{x}))); - fees += out_msg->fwd_fee_; - fees += out_msg->ihr_fee_; - out_msgs.push_back(std::move(out_msg)); + case block::gen::CommonMsgInfo::ext_out_msg_info: { + block::gen::CommonMsgInfo::Record_ext_out_msg_info msg_info; + if (!tlb::csr_unpack(message.info, msg_info)) { + return td::Status::Error("Failed to unpack CommonMsgInfo::ext_out_msg_info"); + } + TRY_RESULT(src, to_std_address(msg_info.src)); + return tonlib_api::make_object(std::move(src), "", 0, 0, 0, 0, std::move(body_hash), + std::move(data)); } } - td::RefInt256 storage_fees; - if (!block::tlb::t_TransactionDescr.get_storage_fees(trans.description, storage_fees)) { - return td::Status::Error("Failed to fetch storage fee from transaction"); + + return td::Status::Error("Unknown CommonMsgInfo tag"); + } + + td::Result> to_raw_message(td::Ref cell) { + return TRY_VM(to_raw_message_or_throw(std::move(cell))); + } + + td::Result> to_raw_transaction_or_throw( + block::Transaction::Info&& info) { + std::string data; + + tonlib_api::object_ptr in_msg; + std::vector> out_msgs; + td::int64 fees = 0; + td::int64 storage_fee = 0; + if (info.transaction.not_null()) { + data = to_bytes(info.transaction); + block::gen::Transaction::Record trans; + if (!tlb::unpack_cell(info.transaction, trans)) { + return td::Status::Error("Failed to unpack Transaction"); + } + + TRY_RESULT_ASSIGN(fees, to_balance(trans.total_fees)); + //LOG(ERROR) << fees; + + //std::ostringstream outp; + //block::gen::t_Transaction.print_ref(outp, info.transaction); + //LOG(INFO) << outp.str(); + + auto is_just = trans.r1.in_msg->prefetch_long(1); + if (is_just == trans.r1.in_msg->fetch_long_eof) { + return td::Status::Error("Failed to parse long"); + } + if (is_just == -1) { + auto msg = trans.r1.in_msg->prefetch_ref(); + TRY_RESULT(in_msg_copy, to_raw_message(trans.r1.in_msg->prefetch_ref())); + in_msg = std::move(in_msg_copy); + } + + if (trans.outmsg_cnt != 0) { + vm::Dictionary dict{trans.r1.out_msgs, 15}; + for (int x = 0; x < trans.outmsg_cnt && x < 100; x++) { + TRY_RESULT(out_msg, to_raw_message(dict.lookup_ref(td::BitArray<15>{x}))); + fees += out_msg->fwd_fee_; + fees += out_msg->ihr_fee_; + out_msgs.push_back(std::move(out_msg)); + } + } + td::RefInt256 storage_fees; + if (!block::tlb::t_TransactionDescr.get_storage_fees(trans.description, storage_fees)) { + return td::Status::Error("Failed to fetch storage fee from transaction"); + } + storage_fee = storage_fees->to_long(); } - storage_fee = storage_fees->to_long(); - } - return tonlib_api::make_object( - info.now, data, - tonlib_api::make_object(info.prev_trans_lt, - info.prev_trans_hash.as_slice().str()), - fees, storage_fee, fees - storage_fee, std::move(in_msg), std::move(out_msgs)); -} - -td::Result> to_raw_transaction(block::Transaction::Info&& info) { - return TRY_VM(to_raw_transaction_or_throw(std::move(info))); -} - -td::Result> to_raw_transactions( - block::TransactionList::Info&& info) { - std::vector> transactions; - for (auto& transaction : info.transactions) { - TRY_RESULT(raw_transaction, to_raw_transaction(std::move(transaction))); - transactions.push_back(std::move(raw_transaction)); + return tonlib_api::make_object( + info.now, data, + tonlib_api::make_object(info.prev_trans_lt, + info.prev_trans_hash.as_slice().str()), + fees, storage_fee, fees - storage_fee, std::move(in_msg), std::move(out_msgs)); } - auto transaction_id = - tonlib_api::make_object(info.lt, info.hash.as_slice().str()); - for (auto& transaction : transactions) { - std::swap(transaction->transaction_id_, transaction_id); + td::Result> to_raw_transaction(block::Transaction::Info&& info) { + return TRY_VM(to_raw_transaction_or_throw(std::move(info))); } - return tonlib_api::make_object(std::move(transactions), std::move(transaction_id)); -} + td::Result> to_raw_transactions( + block::TransactionList::Info&& info) { + std::vector> transactions; + for (auto& transaction : info.transactions) { + TRY_RESULT(raw_transaction, to_raw_transaction(std::move(transaction))); + transactions.push_back(std::move(raw_transaction)); + } + + auto transaction_id = + tonlib_api::make_object(info.lt, info.hash.as_slice().str()); + for (auto& transaction : transactions) { + std::swap(transaction->transaction_id_, transaction_id); + } + + return tonlib_api::make_object(std::move(transactions), std::move(transaction_id)); + } +}; // Raw @@ -1559,39 +2036,16 @@ td::Status TonlibClient::do_request(const tonlib_api::raw_createAndSendMessage& } td::Status TonlibClient::do_request(tonlib_api::raw_getAccountState& request, - td::Promise>&& promise) { + td::Promise>&& promise) { if (!request.account_address_) { return TonlibError::EmptyField("account_address"); } TRY_RESULT(account_address, get_account_address(request.account_address_->account_address_)); - make_request(int_api::GetAccountState{std::move(account_address)}, - promise.wrap([](auto&& res) { return res->to_raw_accountState(); })); + make_request(int_api::GetAccountState{std::move(account_address), query_context_.block_id.copy()}, + promise.wrap([](auto&& res) { return res->to_raw_fullAccountState(); })); return td::Status::OK(); } -td::Status TonlibClient::do_request(tonlib_api::raw_getTransactions& request, - td::Promise>&& promise) { - if (!request.account_address_) { - return TonlibError::EmptyField("account_address"); - } - if (!request.from_transaction_id_) { - return TonlibError::EmptyField("from_transaction_id"); - } - TRY_RESULT(account_address, get_account_address(request.account_address_->account_address_)); - auto lt = request.from_transaction_id_->lt_; - auto hash_str = request.from_transaction_id_->hash_; - if (hash_str.size() != 32) { - return td::Status::Error(400, "Invalid transaction id hash size"); - } - td::Bits256 hash; - hash.as_slice().copy_from(hash_str); - - auto actor_id = actor_id_++; - actors_[actor_id] = td::actor::create_actor( - "GetTransactionHistory", client_.get_client(), account_address, lt, hash, actor_shared(this, actor_id), - promise.wrap(to_raw_transactions)); - return td::Status::OK(); -} td::Result from_tonlib(tonlib_api::inputKeyRegular& input_key) { if (!input_key.key_) { return TonlibError::EmptyField("key"); @@ -1603,196 +2057,133 @@ td::Result from_tonlib(tonlib_api::inputKeyRegular& input_ } td::Result from_tonlib(tonlib_api::InputKey& input_key) { - td::Result r_key; - tonlib_api::downcast_call( - input_key, td::overloaded([&](tonlib_api::inputKeyRegular& input_key) { r_key = from_tonlib(input_key); }, - [&](tonlib_api::inputKeyFake&) { r_key = KeyStorage::fake_input_key(); })); - return r_key; + return downcast_call2>( + input_key, td::overloaded([&](tonlib_api::inputKeyRegular& input_key) { return from_tonlib(input_key); }, + [&](tonlib_api::inputKeyFake&) { return KeyStorage::fake_input_key(); })); } -// ton::TestWallet -td::Status TonlibClient::do_request(const tonlib_api::testWallet_init& request, - td::Promise>&& promise) { - if (!request.private_key_) { - return td::Status::Error(400, "Field private_key must not be empty"); +td::Status TonlibClient::do_request(tonlib_api::raw_getTransactions& request, + td::Promise>&& promise) { + if (!request.account_address_) { + return TonlibError::EmptyField("account_address"); } - TRY_RESULT(input_key, from_tonlib(*request.private_key_)); - auto init_state = ton::TestWallet::get_init_state(td::Ed25519::PublicKey(input_key.key.public_key.copy())); - auto address = ton::GenericAccount::get_address(0 /*zerochain*/, init_state); - TRY_RESULT(private_key, key_storage_.load_private_key(std::move(input_key))); - auto init_message = ton::TestWallet::get_init_message(td::Ed25519::PrivateKey(std::move(private_key.private_key))); - auto message = ton::GenericAccount::create_ext_message(address, std::move(init_state), std::move(init_message)); - make_request(int_api::SendMessage{std::move(message)}, to_any_promise(std::move(promise))); + if (!request.from_transaction_id_) { + return TonlibError::EmptyField("from_transaction_id"); + } + TRY_RESULT(account_address, get_account_address(request.account_address_->account_address_)); + td::optional private_key; + if (request.private_key_) { + TRY_RESULT(input_key, from_tonlib(*request.private_key_)); + //NB: options has lot of problems. We use emplace to migitate them + td::optional o_status; + //NB: rely on (and assert) that GetPrivateKey is a synchonous request + make_request(int_api::GetPrivateKey{std::move(input_key)}, [&](auto&& r_key) { + if (r_key.is_error()) { + o_status.emplace(r_key.move_as_error()); + return; + } + o_status.emplace(td::Status::OK()); + private_key = td::Ed25519::PrivateKey(std::move(r_key.move_as_ok().private_key)); + }); + TRY_STATUS(o_status.unwrap()); + } + auto lt = request.from_transaction_id_->lt_; + auto hash_str = request.from_transaction_id_->hash_; + if (hash_str.size() != 32) { + return td::Status::Error(400, "Invalid transaction id hash size"); + } + td::Bits256 hash; + hash.as_slice().copy_from(hash_str); + + auto actor_id = actor_id_++; + actors_[actor_id] = td::actor::create_actor( + "GetTransactionHistory", client_.get_client(), account_address, lt, hash, actor_shared(this, actor_id), + promise.wrap([private_key = std::move(private_key)](auto&& x) mutable { + return ToRawTransactions(std::move(private_key)).to_raw_transactions(std::move(x)); + })); return td::Status::OK(); } -td::Status TonlibClient::do_request(const tonlib_api::testWallet_sendGrams& request, - td::Promise>&& promise) { - if (!request.destination_) { - return TonlibError::EmptyField("destination"); - } - if (!request.private_key_) { - return TonlibError::EmptyField("private_key"); - } - if (request.message_.size() > ton::TestWallet::max_message_size) { - return TonlibError::MessageTooLong(); - } - TRY_RESULT(account_address, get_account_address(request.destination_->account_address_)); - TRY_RESULT(input_key, from_tonlib(*request.private_key_)); - auto address = ton::GenericAccount::get_address( - 0 /*zerochain*/, ton::TestWallet::get_init_state(td::Ed25519::PublicKey(input_key.key.public_key.copy()))); - TRY_RESULT(private_key_str, key_storage_.load_private_key(std::move(input_key))); - auto private_key = td::Ed25519::PrivateKey(std::move(private_key_str.private_key)); - td::Ref init_state; - if (request.seqno_ == 0) { - TRY_RESULT_PREFIX(public_key, private_key.get_public_key(), TonlibError::Internal()); - init_state = ton::TestWallet::get_init_state(public_key); - } - auto message = ton::TestWallet::make_a_gift_message(private_key, request.seqno_, request.amount_, request.message_, - account_address); - auto message_hash = message->get_hash().as_slice().str(); - auto new_promise = promise.wrap([message_hash = std::move(message_hash)](auto&&) { - return tonlib_api::make_object(0, std::move(message_hash)); - }); - - auto ext_message = ton::GenericAccount::create_ext_message(address, std::move(init_state), std::move(message)); - make_request(int_api::SendMessage{std::move(message)}, std::move(new_promise)); - return td::Status::OK(); -} - -td::Status TonlibClient::do_request(tonlib_api::testWallet_getAccountState& request, - td::Promise>&& promise) { +td::Status TonlibClient::do_request(const tonlib_api::getAccountState& request, + td::Promise>&& promise) { if (!request.account_address_) { return TonlibError::EmptyField("account_address"); } TRY_RESULT(account_address, get_account_address(request.account_address_->account_address_)); - make_request(int_api::GetAccountState{std::move(account_address)}, - promise.wrap([](auto&& res) { return res->to_testWallet_accountState(); })); + make_request(int_api::GetAccountState{std::move(account_address), query_context_.block_id.copy()}, + promise.wrap([](auto&& res) { return res->to_fullAccountState(); })); return td::Status::OK(); } -// ton::Wallet -td::Status TonlibClient::do_request(const tonlib_api::wallet_init& request, - td::Promise>&& promise) { - if (!request.private_key_) { - return TonlibError::EmptyField("private_key"); - } - TRY_RESULT(input_key, from_tonlib(*request.private_key_)); - auto init_state = ton::Wallet::get_init_state(td::Ed25519::PublicKey(input_key.key.public_key.copy())); - auto address = ton::GenericAccount::get_address(0 /*zerochain*/, init_state); - TRY_RESULT(private_key, key_storage_.load_private_key(std::move(input_key))); - auto init_message = ton::Wallet::get_init_message(td::Ed25519::PrivateKey(std::move(private_key.private_key))); - auto message = - ton::GenericAccount::create_ext_message(std::move(address), std::move(init_state), std::move(init_message)); - - make_request(int_api::SendMessage{std::move(message)}, to_any_promise(std::move(promise))); - return td::Status::OK(); -} - -td::Status TonlibClient::do_request(const tonlib_api::wallet_sendGrams& request, - td::Promise>&& promise) { - if (!request.destination_) { - return TonlibError::EmptyField("destination"); - } - if (!request.private_key_) { - return TonlibError::EmptyField("private_key"); - } - if (request.message_.size() > ton::Wallet::max_message_size) { - return TonlibError::MessageTooLong(); - } - TRY_RESULT_PREFIX(valid_until, td::narrow_cast_safe(request.valid_until_), - TonlibError::InvalidField("valid_until", "overflow")); - TRY_RESULT(account_address, get_account_address(request.destination_->account_address_)); - TRY_RESULT(input_key, from_tonlib(*request.private_key_)); - auto address = ton::GenericAccount::get_address( - 0 /*zerochain*/, ton::Wallet::get_init_state(td::Ed25519::PublicKey(input_key.key.public_key.copy()))); - TRY_RESULT(private_key_str, key_storage_.load_private_key(std::move(input_key))); - auto private_key = td::Ed25519::PrivateKey(std::move(private_key_str.private_key)); - td::Ref init_state; - if (request.seqno_ == 0) { - TRY_RESULT_PREFIX(public_key, private_key.get_public_key(), TonlibError::Internal()); - init_state = ton::Wallet::get_init_state(public_key); - } - auto message = ton::Wallet::make_a_gift_message(private_key, request.seqno_, valid_until, request.amount_, - request.message_, account_address); - auto message_hash = message->get_hash().as_slice().str(); - auto new_promise = promise.wrap([valid_until, message_hash = std::move(message_hash)](auto&&) { - return tonlib_api::make_object(valid_until, std::move(message_hash)); - }); - auto ext_message = ton::GenericAccount::create_ext_message(address, std::move(init_state), std::move(message)); - make_request(int_api::SendMessage{std::move(message)}, std::move(new_promise)); - return td::Status::OK(); -} - -td::Status TonlibClient::do_request(tonlib_api::wallet_getAccountState& request, - td::Promise>&& promise) { - if (!request.account_address_) { - return TonlibError::EmptyField("account_address"); - } - TRY_RESULT(account_address, get_account_address(request.account_address_->account_address_)); - make_request(int_api::GetAccountState{std::move(account_address)}, - promise.wrap([](auto&& res) { return res->to_wallet_accountState(); })); - return td::Status::OK(); -} - -// ton::TestGiver -td::Status TonlibClient::do_request(const tonlib_api::testGiver_sendGrams& request, - td::Promise>&& promise) { - if (!request.destination_) { - return TonlibError::EmptyField("destination"); - } - if (request.message_.size() > ton::TestGiver::max_message_size) { - return TonlibError::MessageTooLong(); - } - TRY_RESULT(account_address, get_account_address(request.destination_->account_address_)); - auto message = - ton::TestGiver::make_a_gift_message(request.seqno_, request.amount_, request.message_, account_address); - auto message_hash = message->get_hash().as_slice().str(); - auto new_promise = promise.wrap([message_hash = std::move(message_hash)](auto&&) { - return tonlib_api::make_object(0, std::move(message_hash)); - }); - - auto ext_message = ton::GenericAccount::create_ext_message(ton::TestGiver::address(), {}, std::move(message)); - make_request(int_api::SendMessage{std::move(message)}, std::move(new_promise)); - return td::Status::OK(); -} - -td::Status TonlibClient::do_request(const tonlib_api::testGiver_getAccountState& request, - td::Promise>&& promise) { - make_request(int_api::GetAccountState{ton::TestGiver::address()}, - promise.wrap([](auto&& res) { return res->to_testGiver_accountState(); })); - return td::Status::OK(); -} - -td::Status TonlibClient::do_request(const tonlib_api::generic_getAccountState& request, - td::Promise>&& promise) { - if (!request.account_address_) { - return TonlibError::EmptyField("account_address"); - } - TRY_RESULT(account_address, get_account_address(request.account_address_->account_address_)); - make_request(int_api::GetAccountState{std::move(account_address)}, - promise.wrap([](auto&& res) { return res->to_generic_accountState(); })); - return td::Status::OK(); +td::Result to_dns_entry_data(tonlib_api::dns_EntryData& entry_data) { + using R = td::Result; + return downcast_call2( + entry_data, + td::overloaded( + [&](tonlib_api::dns_entryDataUnknown& unknown) -> R { return ton::ManualDns::EntryData(); }, + [&](tonlib_api::dns_entryDataNextResolver& next_resolver) -> R { + if (!next_resolver.resolver_) { + return TonlibError::EmptyField("resolver"); + } + TRY_RESULT(resolver, get_account_address(next_resolver.resolver_->account_address_)); + return ton::ManualDns::EntryData::next_resolver(std::move(resolver)); + }, + [&](tonlib_api::dns_entryDataSmcAddress& smc_address) -> R { + if (!smc_address.smc_address_) { + return TonlibError::EmptyField("smc_address"); + } + TRY_RESULT(address, get_account_address(smc_address.smc_address_->account_address_)); + return ton::ManualDns::EntryData::smc_address(std::move(address)); + }, + [&](tonlib_api::dns_entryDataAdnlAddress& adnl_address) -> R { + if (!adnl_address.adnl_address_) { + return TonlibError::EmptyField("adnl_address"); + } + TRY_RESULT(address, get_adnl_address(adnl_address.adnl_address_->adnl_address_)); + return ton::ManualDns::EntryData::adnl_address(std::move(address)); + }, + [&](tonlib_api::dns_entryDataText& text) -> R { return ton::ManualDns::EntryData::text(text.text_); })); } class GenericCreateSendGrams : public TonlibQueryActor { public: - GenericCreateSendGrams(td::actor::ActorShared client, - tonlib_api::generic_createSendGramsQuery send_grams, - td::Promise>&& promise) - : TonlibQueryActor(std::move(client)), send_grams_(std::move(send_grams)), promise_(std::move(promise)) { + GenericCreateSendGrams(td::actor::ActorShared client, tonlib_api::createQuery query, + td::optional block_id, td::Promise>&& promise) + : TonlibQueryActor(std::move(client)) + , query_(std::move(query)) + , promise_(std::move(promise)) + , block_id_(std::move(block_id)) { } private: - tonlib_api::generic_createSendGramsQuery send_grams_; + tonlib_api::createQuery query_; td::Promise> promise_; td::unique_ptr source_; - td::unique_ptr destination_; + std::vector> destinations_; + size_t destinations_left_ = 0; bool has_private_key_{false}; bool is_fake_key_{false}; td::optional private_key_; td::optional public_key_; + td::optional block_id_; + + struct Action { + block::StdAddress destination; + td::int64 amount; + + bool is_encrypted{false}; + bool should_encrypt; + std::string message; + + td::Ref body; + }; + bool allow_send_to_uninited_{false}; + std::vector actions_; + + // We combine compelty different actions in one actor + // Should be splitted eventually + std::vector dns_actions_; void check(td::Status status) { if (status.is_error()) { @@ -1808,40 +2199,136 @@ class GenericCreateSendGrams : public TonlibQueryActor { check(TonlibError::Cancelled()); } - td::Status do_start_up() { - if (send_grams_.timeout_ < 0 || send_grams_.timeout_ > 300) { - return TonlibError::InvalidField("timeout", "must be between 0 and 300"); + td::Result to_action(const tonlib_api::msg_message& message) { + if (!message.destination_) { + return TonlibError::EmptyField("message.destination"); } - if (!send_grams_.destination_) { - return TonlibError::EmptyField("destination"); - } - if (!send_grams_.source_) { - return TonlibError::EmptyField("source"); - } - if (send_grams_.amount_ < 0) { + Action res; + TRY_RESULT(destination, get_account_address(message.destination_->account_address_)); + res.destination = destination; + if (message.amount_ < 0) { return TonlibError::InvalidField("amount", "can't be negative"); } + res.amount = message.amount_; + auto status = + downcast_call2(*message.data_, td::overloaded( + [&](tonlib_api::msg_dataRaw& text) { + TRY_RESULT(body, vm::std_boc_deserialize(text.body_)); + res.body = std::move(body); + return td::Status::OK(); + }, + [&](tonlib_api::msg_dataText& text) { + res.message = text.text_; + res.should_encrypt = false; + res.is_encrypted = false; + return td::Status::OK(); + }, + [&](tonlib_api::msg_dataDecryptedText& text) { + res.message = text.text_; + if (!has_private_key_) { + return TonlibError::EmptyField("input_key"); + } + res.should_encrypt = true; + res.is_encrypted = true; + return td::Status::OK(); + }, + [&](tonlib_api::msg_dataEncryptedText& text) { + res.message = text.text_; + res.should_encrypt = false; + res.is_encrypted = true; + return td::Status::OK(); + })); // Use this limit as a preventive check - if (send_grams_.message_.size() > ton::Wallet::max_message_size) { + if (res.message.size() > ton::Wallet::max_message_size) { return TonlibError::MessageTooLong(); } - TRY_RESULT(destination_address, get_account_address(send_grams_.destination_->account_address_)); - TRY_RESULT(source_address, get_account_address(send_grams_.source_->account_address_)); + TRY_STATUS(std::move(status)); + return res; + } - has_private_key_ = bool(send_grams_.private_key_); + td::Result to_dns_action(tonlib_api::dns_Action& action) { + using R = td::Result; + return downcast_call2(action, + td::overloaded( + [&](tonlib_api::dns_actionDeleteAll& del_all) -> R { + return ton::ManualDns::Action{"", 0, {}}; + }, + [&](tonlib_api::dns_actionDelete& del) -> R { + TRY_RESULT(category, td::narrow_cast_safe(del.category_)); + return ton::ManualDns::Action{del.name_, category, {}}; + }, + [&](tonlib_api::dns_actionSet& set) -> R { + if (!set.entry_) { + return TonlibError::EmptyField("entry"); + } + if (!set.entry_->entry_) { + return TonlibError::EmptyField("entry.entry"); + } + TRY_RESULT(category, td::narrow_cast_safe(set.entry_->category_)); + TRY_RESULT(entry_data, to_dns_entry_data(*set.entry_->entry_)); + TRY_RESULT(data_cell, entry_data.as_cell()); + return ton::ManualDns::Action{set.entry_->name_, category, std::move(data_cell)}; + })); + } + + td::Status parse_action(tonlib_api::Action& action) { + return downcast_call2(action, + td::overloaded([&](tonlib_api::actionNoop& cell) { return td::Status::OK(); }, + [&](tonlib_api::actionMsg& cell) { + allow_send_to_uninited_ = cell.allow_send_to_uninited_; + for (auto& from_action : cell.messages_) { + if (!from_action) { + return TonlibError::EmptyField("message"); + } + TRY_RESULT(action, to_action(*from_action)); + actions_.push_back(std::move(action)); + } + return td::Status::OK(); + }, + [&](tonlib_api::actionDns& cell) { + for (auto& from_action : cell.actions_) { + if (!from_action) { + return TonlibError::EmptyField("action"); + } + TRY_RESULT(action, to_dns_action(*from_action)); + dns_actions_.push_back(std::move(action)); + } + return td::Status::OK(); + })); + } + + td::Status do_start_up() { + if (query_.timeout_ < 0 || query_.timeout_ > 300) { + return TonlibError::InvalidField("timeout", "must be between 0 and 300"); + } + if (!query_.address_) { + return TonlibError::EmptyField("address"); + } + if (!query_.action_) { + return TonlibError::EmptyField("action"); + } + + TRY_RESULT(source_address, get_account_address(query_.address_->account_address_)); + + has_private_key_ = bool(query_.private_key_); if (has_private_key_) { - TRY_RESULT(input_key, from_tonlib(*send_grams_.private_key_)); - is_fake_key_ = send_grams_.private_key_->get_id() == tonlib_api::inputKeyFake::ID; + TRY_RESULT(input_key, from_tonlib(*query_.private_key_)); + is_fake_key_ = query_.private_key_->get_id() == tonlib_api::inputKeyFake::ID; public_key_ = td::Ed25519::PublicKey(input_key.key.public_key.copy()); send_query(int_api::GetPrivateKey{std::move(input_key)}, promise_send_closure(actor_id(this), &GenericCreateSendGrams::on_private_key)); } + TRY_STATUS(parse_action(*query_.action_)); - send_query(int_api::GetAccountState{source_address}, + send_query(int_api::GetAccountState{source_address, block_id_.copy()}, promise_send_closure(actor_id(this), &GenericCreateSendGrams::on_source_state)); - send_query(int_api::GetAccountState{destination_address}, - promise_send_closure(actor_id(this), &GenericCreateSendGrams::on_destination_state)); + destinations_.resize(actions_.size()); + destinations_left_ = destinations_.size(); + for (size_t i = 0; i < actions_.size(); i++) { + send_query(int_api::GetAccountState{actions_[i].destination, block_id_.copy()}, + promise_send_closure(actor_id(this), &GenericCreateSendGrams::on_destination_state, i)); + } return do_loop(); } @@ -1875,109 +2362,157 @@ class GenericCreateSendGrams : public TonlibQueryActor { return do_loop(); } - void on_destination_state(td::Result> r_state) { - check(do_on_destination_state(std::move(r_state))); + void on_destination_state(size_t i, td::Result> state) { + check(do_on_destination_state(i, std::move(state))); } - td::Status do_on_destination_state(td::Result> r_state) { + td::Status do_on_destination_state(size_t i, td::Result> r_state) { TRY_RESULT(state, std::move(r_state)); - destination_ = std::move(state); - if (destination_->is_frozen()) { + CHECK(destinations_left_ > 0); + destinations_left_--; + destinations_[i] = std::move(state); + auto& destination = *destinations_[i]; + if (destination.is_frozen()) { //FIXME: after restoration of frozen accounts will be supported return TonlibError::TransferToFrozen(); } - if (destination_->get_wallet_type() == AccountState::Empty && destination_->get_address().bounceable) { - if (!send_grams_.allow_send_to_uninited_) { + if (destination.get_wallet_type() == AccountState::Empty && destination.get_address().bounceable) { + if (!allow_send_to_uninited_) { return TonlibError::DangerousTransaction("Transfer to uninited wallet"); } - destination_->make_non_bounceable(); + destination.make_non_bounceable(); LOG(INFO) << "Change destination address from bounceable to non-bounceable "; } return do_loop(); } + td::Status do_dns_loop() { + if (!private_key_) { + return TonlibError::EmptyField("private_key"); + } + + Query::Raw raw; + auto valid_until = source_->get_sync_time(); + valid_until += query_.timeout_ == 0 ? 60 : query_.timeout_; + raw.valid_until = valid_until; + auto dns = ton::ManualDns::create(source_->get_smc_state()); + if (dns_actions_.empty()) { + TRY_RESULT(message_body, dns->create_init_query(private_key_.value(), valid_until)); + raw.message_body = std::move(message_body); + } else { + TRY_RESULT(message_body, dns->create_update_query(private_key_.value(), dns_actions_, valid_until)); + raw.message_body = std::move(message_body); + } + raw.new_state = source_->get_new_state(); + raw.message = ton::GenericAccount::create_ext_message(source_->get_address(), raw.new_state, raw.message_body); + raw.source = std::move(source_); + raw.destinations = std::move(destinations_); + promise_.set_value(td::make_unique(std::move(raw))); + stop(); + return td::Status::OK(); + } + td::Status do_loop() { - if (!source_ || !destination_) { + if (!source_ || destinations_left_ != 0) { return td::Status::OK(); } if (has_private_key_ && !private_key_) { return td::Status::OK(); } - Query::Raw raw; + if (source_->get_wallet_type() == AccountState::ManualDns) { + return do_dns_loop(); + } - auto amount = send_grams_.amount_; - if (amount > source_->get_balance()) { - return TonlibError::NotEnoughFunds(); - } - if (amount == source_->get_balance()) { - amount = -1; - } - auto message = send_grams_.message_; switch (source_->get_wallet_type()) { case AccountState::Empty: return TonlibError::AccountNotInited(); case AccountState::Unknown: return TonlibError::AccountTypeUnknown(); - case AccountState::Giver: { - raw.message_body = ton::TestGiver::make_a_gift_message(0, amount, message, destination_->get_address()); + default: break; - } - - case AccountState::SimpleWallet: { - if (!private_key_) { - return TonlibError::EmptyField("private_key"); - } - if (message.size() > ton::TestWallet::max_message_size) { - return TonlibError::MessageTooLong(); - } - TRY_RESULT(seqno, ton::TestWallet(source_->get_smc_state()).get_seqno()); - raw.message_body = ton::TestWallet::make_a_gift_message(private_key_.unwrap(), seqno, amount, message, - destination_->get_address()); - break; - } - case AccountState::Wallet: { - if (!private_key_) { - return TonlibError::EmptyField("private_key"); - } - if (message.size() > ton::Wallet::max_message_size) { - return TonlibError::MessageTooLong(); - } - TRY_RESULT(seqno, ton::Wallet(source_->get_smc_state()).get_seqno()); - auto valid_until = source_->get_sync_time(); - valid_until += send_grams_.timeout_ == 0 ? 60 : send_grams_.timeout_; - raw.valid_until = valid_until; - raw.message_body = ton::Wallet::make_a_gift_message(private_key_.unwrap(), seqno, valid_until, amount, message, - destination_->get_address()); - break; - } - case AccountState::WalletV3: { - if (!private_key_) { - return TonlibError::EmptyField("private_key"); - } - if (message.size() > ton::WalletV3::max_message_size) { - return TonlibError::MessageTooLong(); - } - auto wallet = ton::WalletV3(source_->get_smc_state()); - TRY_RESULT(seqno, wallet.get_seqno()); - TRY_RESULT(wallet_id, wallet.get_wallet_id()); - auto valid_until = source_->get_sync_time(); - valid_until += send_grams_.timeout_ == 0 ? 60 : send_grams_.timeout_; - raw.valid_until = valid_until; - raw.message_body = ton::WalletV3::make_a_gift_message(private_key_.unwrap(), wallet_id, seqno, valid_until, - amount, message, destination_->get_address()); - break; - } } - raw.new_state = source_->get_new_state(); - raw.message = ton::GenericAccount::create_ext_message(source_->get_address(), raw.new_state, raw.message_body); - raw.source = std::move(source_); - raw.destination = std::move(destination_); + if (!source_->is_wallet()) { + return TonlibError::AccountActionUnsupported("wallet action"); + } - promise_.set_value(td::make_unique(std::move(raw))); - stop(); - return td::Status::OK(); + td::int64 amount = 0; + for (auto& action : actions_) { + amount += action.amount; + } + + if (amount > source_->get_balance()) { + return TonlibError::NotEnoughFunds(); + } + + auto valid_until = source_->get_sync_time(); + valid_until += query_.timeout_ == 0 ? 60 : query_.timeout_; + std::vector gifts; + size_t i = 0; + for (auto& action : actions_) { + ton::HighloadWalletV2::Gift gift; + auto& destination = destinations_[i]; + gift.destination = destinations_[i]->get_address(); + gift.gramms = action.amount; + if (action.amount == source_->get_balance()) { + gift.gramms = -1; + } + if (action.body.not_null()) { + gift.body = action.body; + } else if (action.should_encrypt) { + LOG(ERROR) << "TRY ENCRYPT"; + if (!private_key_) { + return TonlibError::EmptyField("private_key"); + } + if (!destination->is_wallet()) { + return TonlibError::MessageEncryption("Get public key (in destination)"); + } + auto wallet = destination->get_wallet(); + TRY_RESULT_PREFIX(public_key, wallet->get_public_key(), + TonlibError::AccountActionUnsupported(PSLICE() << "Get public key (in destination) : " + << destination->get_wallet_type())); + TRY_RESULT_PREFIX(encrypted_message, + SimpleEncryptionV2::encrypt_data(action.message, public_key, private_key_.value()), + TonlibError::Internal()); + gift.message = encrypted_message.as_slice().str(); + gift.is_encrypted = true; + } else { + gift.message = action.message; + gift.is_encrypted = action.is_encrypted; + } + i++; + gifts.push_back(gift); + } + + Query::Raw raw; + auto with_wallet = [&](auto&& wallet) { + if (!private_key_) { + return TonlibError::EmptyField("private_key"); + } + if (wallet.get_max_gifts_size() < gifts.size()) { + return TonlibError::MessageTooLong(); // TODO: other error + } + + raw.valid_until = valid_until; + TRY_RESULT(message_body, wallet.make_a_gift_message(private_key_.unwrap(), valid_until, gifts)); + raw.message_body = std::move(message_body); + raw.new_state = source_->get_new_state(); + raw.message = ton::GenericAccount::create_ext_message(source_->get_address(), raw.new_state, raw.message_body); + raw.source = std::move(source_); + raw.destinations = std::move(destinations_); + + promise_.set_value(td::make_unique(std::move(raw))); + stop(); + return td::Status::OK(); + }; + + if (source_->get_wallet_type() == AccountState::Giver) { + valid_until = 0; + private_key_ = td::Ed25519::PrivateKey(td::SecureString(std::string(32, '\0'))); + } + + return with_wallet(*source_->get_wallet()); } }; @@ -2002,24 +2537,50 @@ void TonlibClient::finish_create_query(td::Result> r_query auto id = register_query(std::move(query)); promise.set_result(get_query_info(id)); } -void TonlibClient::finish_send_query(td::Result> r_query, - td::Promise>&& promise) { - TRY_RESULT_PROMISE(promise, query, std::move(r_query)); - auto result = tonlib_api::make_object(query->get_valid_until(), - query->get_body_hash().as_slice().str()); - auto id = register_query(std::move(query)); - make_request(tonlib_api::query_send(id), - promise.wrap([result = std::move(result)](auto&&) mutable { return std::move(result); })); -} -td::Status TonlibClient::do_request(tonlib_api::generic_createSendGramsQuery& request, + +td::Status TonlibClient::do_request(tonlib_api::createQuery& request, td::Promise>&& promise) { auto id = actor_id_++; actors_[id] = td::actor::create_actor( - "GenericSendGrams", actor_shared(this, id), std::move(request), + "GenericSendGrams", actor_shared(this, id), std::move(request), query_context_.block_id.copy(), promise.send_closure(actor_id(this), &TonlibClient::finish_create_query)); return td::Status::OK(); } +td::Status TonlibClient::do_request(tonlib_api::msg_decrypt& request, + td::Promise>&& promise) { + if (!request.input_key_) { + return TonlibError::EmptyField("input_key"); + } + if (!request.data_) { + return TonlibError::EmptyField("data"); + } + TRY_RESULT(input_key, from_tonlib(*request.input_key_)); + make_request( + int_api::GetPrivateKey{std::move(input_key)}, + promise.wrap([elements = std::move(request.data_)](auto key) mutable { + auto private_key = td::Ed25519::PrivateKey(std::move(key.private_key)); + elements->elements_ = td::transform(std::move(elements->elements_), [&private_key](auto msg) { + if (!msg) { + return std::move(msg); + } + using ReturnType = tonlib_api::object_ptr; + return downcast_call2( + *msg, td::overloaded([&msg](auto&) { return std::move(msg); }, + [&msg, &private_key](tonlib_api::msg_dataEncryptedText& encrypted) -> ReturnType { + auto r_decrypted = SimpleEncryptionV2::decrypt_data(encrypted.text_, private_key); + if (r_decrypted.is_error()) { + return std::move(msg); + } + return tonlib_api::make_object( + r_decrypted.move_as_ok().as_slice().str()); + })); + }); + return std::move(elements); + })); + return td::Status::OK(); +} + td::Status TonlibClient::do_request(const tonlib_api::raw_createQuery& request, td::Promise>&& promise) { if (!request.destination_) { @@ -2038,7 +2599,7 @@ td::Status TonlibClient::do_request(const tonlib_api::raw_createQuery& request, td::Promise> new_promise = promise.send_closure(actor_id(this), &TonlibClient::finish_create_query); - make_request(int_api::GetAccountState{account_address}, + make_request(int_api::GetAccountState{account_address, query_context_.block_id.copy()}, new_promise.wrap([smc_state = std::move(smc_state), body = std::move(body)](auto&& source) mutable { Query::Raw raw; if (smc_state) { @@ -2049,24 +2610,11 @@ td::Status TonlibClient::do_request(const tonlib_api::raw_createQuery& request, raw.message = ton::GenericAccount::create_ext_message(source->get_address(), raw.new_state, raw.message_body); raw.source = std::move(source); - raw.destination = nullptr; return td::make_unique(std::move(raw)); })); return td::Status::OK(); } -td::Status TonlibClient::do_request(tonlib_api::generic_sendGrams& request, - td::Promise>&& promise) { - auto id = actor_id_++; - actors_[id] = td::actor::create_actor( - "GenericSendGrams", actor_shared(this, id), - tonlib_api::generic_createSendGramsQuery(std::move(request.private_key_), std::move(request.source_), - std::move(request.destination_), request.amount_, request.timeout_, - request.allow_send_to_uninited_, std::move(request.message_)), - promise.send_closure(actor_id(this), &TonlibClient::finish_send_query)); - return td::Status::OK(); -} - td::Status TonlibClient::do_request(const tonlib_api::query_getInfo& request, td::Promise>&& promise) { promise.set_result(get_query_info(request.id_)); @@ -2083,8 +2631,8 @@ void TonlibClient::query_estimate_fees(td::int64 id, bool ignore_chksig, td::Res TRY_RESULT_PROMISE(promise, state, std::move(r_state)); TRY_RESULT_PROMISE_PREFIX(promise, fees, TRY_VM(it->second->estimate_fees(ignore_chksig, *state.config)), TonlibError::Internal()); - promise.set_value( - tonlib_api::make_object(fees.first.to_tonlib_api(), fees.second.to_tonlib_api())); + promise.set_value(tonlib_api::make_object( + fees.first.to_tonlib_api(), td::transform(fees.second, [](auto& x) { return x.to_tonlib_api(); }))); } td::Status TonlibClient::do_request(const tonlib_api::query_estimateFees& request, @@ -2154,7 +2702,7 @@ td::Status TonlibClient::do_request(const tonlib_api::smc_load& request, return TonlibError::EmptyField("account_address"); } TRY_RESULT(account_address, get_account_address(request.account_address_->account_address_)); - make_request(int_api::GetAccountState{std::move(account_address)}, + make_request(int_api::GetAccountState{std::move(account_address), query_context_.block_id.copy()}, promise.send_closure(actor_id(this), &TonlibClient::finish_load_smc)); return td::Status::OK(); } @@ -2195,6 +2743,98 @@ td::Status TonlibClient::do_request(const tonlib_api::smc_getState& request, return td::Status::OK(); } +bool is_list(vm::StackEntry entry) { + while (true) { + if (entry.type() == vm::StackEntry::Type::t_null) { + return true; + } + if (entry.type() != vm::StackEntry::Type::t_tuple) { + return false; + } + if (entry.as_tuple()->size() != 2) { + return false; + } + entry = entry.as_tuple()->at(1); + } +}; +auto to_tonlib_api(const vm::StackEntry& entry) -> tonlib_api::object_ptr { + switch (entry.type()) { + case vm::StackEntry::Type::t_int: + return tonlib_api::make_object( + tonlib_api::make_object(dec_string(entry.as_int()))); + case vm::StackEntry::Type::t_slice: + return tonlib_api::make_object(tonlib_api::make_object( + to_bytes(vm::CellBuilder().append_cellslice(entry.as_slice()).finalize()))); + case vm::StackEntry::Type::t_cell: + return tonlib_api::make_object( + tonlib_api::make_object(to_bytes(entry.as_cell()))); + case vm::StackEntry::Type::t_null: + case vm::StackEntry::Type::t_tuple: { + std::vector> elements; + if (is_list(entry)) { + auto node = entry; + while (node.type() == vm::StackEntry::Type::t_tuple) { + elements.push_back(to_tonlib_api(node.as_tuple()->at(0))); + node = node.as_tuple()->at(1); + } + return tonlib_api::make_object( + tonlib_api::make_object(std::move(elements))); + + } else { + for (auto& element : *entry.as_tuple()) { + elements.push_back(to_tonlib_api(element)); + } + return tonlib_api::make_object( + tonlib_api::make_object(std::move(elements))); + } + } + + default: + return tonlib_api::make_object(); + } +}; + +td::Result from_tonlib_api(tonlib_api::tvm_StackEntry& entry) { + // TODO: error codes + // downcast_call + return downcast_call2>( + entry, + td::overloaded( + [&](tonlib_api::tvm_stackEntryUnsupported& cell) { return td::Status::Error("Unsuppored stack entry"); }, + [&](tonlib_api::tvm_stackEntrySlice& cell) -> td::Result { + TRY_RESULT(res, vm::std_boc_deserialize(cell.slice_->bytes_)); + return vm::StackEntry{std::move(res)}; + }, + [&](tonlib_api::tvm_stackEntryCell& cell) -> td::Result { + TRY_RESULT(res, vm::std_boc_deserialize(cell.cell_->bytes_)); + return vm::StackEntry{std::move(res)}; + }, + [&](tonlib_api::tvm_stackEntryTuple& tuple) -> td::Result { + std::vector elements; + for (auto& element : tuple.tuple_->elements_) { + TRY_RESULT(new_element, from_tonlib_api(*element)); + elements.push_back(std::move(new_element)); + } + return td::Ref(true, std::move(elements)); + }, + [&](tonlib_api::tvm_stackEntryList& tuple) -> td::Result { + vm::StackEntry tail; + for (auto& element : td::reversed(tuple.list_->elements_)) { + TRY_RESULT(new_element, from_tonlib_api(*element)); + tail = vm::make_tuple_ref(std::move(new_element), std::move(tail)); + } + return tail; + }, + [&](tonlib_api::tvm_stackEntryNumber& number) -> td::Result { + auto& dec = *number.number_; + auto num = td::dec_string_to_int256(dec.number_); + if (num.is_null()) { + return td::Status::Error("Failed to parse dec string to int256"); + } + return num; + })); +} + td::Status TonlibClient::do_request(const tonlib_api::smc_runGetMethod& request, td::Promise>&& promise) { auto it = smcs_.find(request.id_); @@ -2209,72 +2849,137 @@ td::Status TonlibClient::do_request(const tonlib_api::smc_runGetMethod& request, [&](tonlib_api::smc_methodIdName& name) { args.set_method_id(name.name_); })); td::Ref stack(true); td::Status status; - // TODO: error codes - // downcast_call for (auto& entry : request.stack_) { - downcast_call(*entry, td::overloaded( - [&](tonlib_api::tvm_stackEntryUnsupported& cell) { - status = td::Status::Error("Unsuppored stack entry"); - }, - [&](tonlib_api::tvm_stackEntrySlice& cell) { - auto r_cell = vm::std_boc_deserialize(cell.slice_->bytes_); - if (r_cell.is_error()) { - status = r_cell.move_as_error(); - return; - } - stack.write().push_cell(r_cell.move_as_ok()); - }, - [&](tonlib_api::tvm_stackEntryCell& cell) { - auto r_cell = vm::std_boc_deserialize(cell.cell_->bytes_); - if (r_cell.is_error()) { - status = r_cell.move_as_error(); - return; - } - stack.write().push_cell(r_cell.move_as_ok()); - }, - [&](tonlib_api::tvm_stackEntryNumber& number) { - [&](tonlib_api::tvm_numberDecimal& dec) { - auto num = td::dec_string_to_int256(dec.number_); - if (num.is_null()) { - status = td::Status::Error("Failed to parse dec string to int256"); - return; - } - stack.write().push_int(std::move(num)); - }(*number.number_); - })); + TRY_RESULT(e, from_tonlib_api(*entry)); + stack.write().push(std::move(e)); } - TRY_STATUS(std::move(status)); args.set_stack(std::move(stack)); auto res = smc->run_get_method(std::move(args)); // smc.runResult gas_used:int53 stack:vector exit_code:int32 = smc.RunResult; std::vector> res_stack; for (auto& entry : res.stack->as_span()) { - switch (entry.type()) { - case vm::StackEntry::Type::t_int: - res_stack.push_back(tonlib_api::make_object( - tonlib_api::make_object(dec_string(entry.as_int())))); - break; - case vm::StackEntry::Type::t_slice: - res_stack.push_back( - tonlib_api::make_object(tonlib_api::make_object( - to_bytes(vm::CellBuilder().append_cellslice(entry.as_slice()).finalize())))); - break; - case vm::StackEntry::Type::t_cell: - res_stack.push_back(tonlib_api::make_object( - tonlib_api::make_object(to_bytes(entry.as_cell())))); - break; - default: - res_stack.push_back(tonlib_api::make_object()); - break; - } + res_stack.push_back(to_tonlib_api(entry)); } promise.set_value(tonlib_api::make_object(res.gas_used, std::move(res_stack), res.code)); return td::Status::OK(); } -td::Status TonlibClient::do_request(tonlib_api::sync& request, td::Promise>&& promise) { - client_.with_last_block(to_any_promise(std::move(promise))); +td::Result> to_tonlib_api( + const ton::ManualDns::EntryData& entry_data) { + td::Result> res; + if (entry_data.data.empty()) { + return TonlibError::Internal("Unexpected empty EntryData"); + } + entry_data.data.visit(td::overloaded( + [&](const ton::ManualDns::EntryDataText& text) { + res = tonlib_api::make_object(text.text); + }, + [&](const ton::ManualDns::EntryDataNextResolver& resolver) { + res = tonlib_api::make_object( + tonlib_api::make_object(resolver.resolver.rserialize(true))); + }, + [&](const ton::ManualDns::EntryDataAdnlAddress& adnl_address) { + res = tonlib_api::make_object( + tonlib_api::make_object( + td::adnl_id_encode(adnl_address.adnl_address.as_slice()).move_as_ok())); + }, + [&](const ton::ManualDns::EntryDataSmcAddress& smc_address) { + res = tonlib_api::make_object( + tonlib_api::make_object(smc_address.smc_address.rserialize(true))); + })); + return res; +} + +void TonlibClient::finish_dns_resolve(std::string name, td::int32 category, td::int32 ttl, + td::optional block_id, DnsFinishData dns_finish_data, + td::Promise>&& promise) { + block_id = dns_finish_data.block_id; + // TODO: check if the smartcontract supports Dns interface + // TODO: should we use some DnsInterface instead of ManualDns? + auto dns = ton::ManualDns::create(dns_finish_data.smc_state); + TRY_RESULT_PROMISE(promise, entries, dns->resolve(name, category)); + + if (entries.size() == 1 && entries[0].category == -1 && entries[0].name != name && ttl > 0 && + entries[0].data.type == ton::ManualDns::EntryData::Type::NextResolver) { + td::Slice got_name = entries[0].name; + if (got_name.size() >= name.size()) { + TRY_STATUS_PROMISE(promise, TonlibError::Internal("domain is too long")); + } + auto dot_position = name.size() - got_name.size() - 1; + auto suffix = name.substr(dot_position + 1); + auto prefix = name.substr(0, dot_position); + if (name[dot_position] != '.') { + TRY_STATUS_PROMISE(promise, td::Status::Error("next resolver error: domain split not at a component boundary ")); + } + if (suffix != got_name) { + TRY_STATUS_PROMISE(promise, TonlibError::Internal("domain is not a suffix of the query")); + } + + auto address = entries[0].data.data.get().resolver; + return do_dns_request(prefix, category, ttl - 1, std::move(block_id), address, std::move(promise)); + } + + std::vector> api_entries; + for (auto& entry : entries) { + TRY_RESULT_PROMISE(promise, entry_data, to_tonlib_api(entry.data)); + api_entries.push_back( + tonlib_api::make_object(entry.name, entry.category, std::move(entry_data))); + } + promise.set_value(tonlib_api::make_object(std::move(api_entries))); +} + +void TonlibClient::do_dns_request(std::string name, td::int32 category, td::int32 ttl, + td::optional block_id, block::StdAddress address, + td::Promise>&& promise) { + auto block_id_copy = block_id.copy(); + td::Promise new_promise = + promise.send_closure(actor_id(this), &TonlibClient::finish_dns_resolve, name, category, ttl, std::move(block_id)); + + if (0) { + make_request(int_api::GetAccountState{address, std::move(block_id_copy)}, + new_promise.wrap([](auto&& account_state) { + return DnsFinishData{account_state->get_block_id(), account_state->get_smc_state()}; + })); + + return; + } + + TRY_RESULT_PROMISE(promise, args, ton::DnsInterface::resolve_args(name, category)); + int_api::RemoteRunSmcMethod query; + query.address = std::move(address); + query.args = std::move(args); + query.block_id = std::move(block_id_copy); + query.need_result = false; + + make_request(std::move(query), new_promise.wrap([](auto&& run_method) { + return DnsFinishData{run_method.block_id, run_method.smc_state}; + })); + ; +} + +td::Status TonlibClient::do_request(const tonlib_api::dns_resolve& request, + td::Promise>&& promise) { + auto block_id = query_context_.block_id.copy(); + if (!request.account_address_) { + make_request(int_api::GetDnsResolver{}, + promise.send_closure(actor_id(this), &TonlibClient::do_dns_request, request.name_, request.category_, + request.ttl_, std::move(block_id))); + return td::Status::OK(); + } + TRY_RESULT(account_address, get_account_address(request.account_address_->account_address_)); + do_dns_request(request.name_, request.category_, request.ttl_, std::move(block_id), account_address, + std::move(promise)); + return td::Status::OK(); +} + +td::Status TonlibClient::do_request(tonlib_api::sync& request, + td::Promise>&& promise) { + // ton.blockIdExt workchain:int32 shard:int64 seqno:int32 root_hash:bytes file_hash:bytes = ton.BlockIdExt; + client_.with_last_block( + std::move(promise).wrap([](auto last_block) -> td::Result> { + return to_tonlib_api(last_block.last_block_id); + })); return td::Status::OK(); } @@ -2385,6 +3090,28 @@ td::Status TonlibClient::do_request(const tonlib_api::importEncryptedKey& reques promise.set_value(tonlib_api::make_object(key_bytes.serialize(true), std::move(key.secret))); return td::Status::OK(); } +td::Status TonlibClient::do_request(const tonlib_api::exportUnencryptedKey& request, + td::Promise>&& promise) { + if (!request.input_key_) { + return TonlibError::EmptyField("input_key"); + } + TRY_RESULT(input_key, from_tonlib(*request.input_key_)); + TRY_RESULT(exported_key, key_storage_.export_unencrypted_key(std::move(input_key))); + promise.set_value(tonlib_api::make_object(std::move(exported_key.data))); + return td::Status::OK(); +} +td::Status TonlibClient::do_request(const tonlib_api::importUnencryptedKey& request, + td::Promise>&& promise) { + if (!request.exported_unencrypted_key_) { + return TonlibError::EmptyField("exported_encrypted_key"); + } + TRY_RESULT(key, key_storage_.import_unencrypted_key( + std::move(request.local_password_), + KeyStorage::ExportedUnencryptedKey{std::move(request.exported_unencrypted_key_->data_)})); + TRY_RESULT(key_bytes, public_key_from_bytes(key.public_key.as_slice())); + promise.set_value(tonlib_api::make_object(key_bytes.serialize(true), std::move(key.secret))); + return td::Status::OK(); +} td::Status TonlibClient::do_request(const tonlib_api::changeLocalPassword& request, td::Promise>&& promise) { @@ -2507,19 +3234,37 @@ td::Status TonlibClient::do_request(int_api::GetAccountState request, td::Promise>&& promise) { auto actor_id = actor_id_++; actors_[actor_id] = td::actor::create_actor( - "GetAccountState", client_.get_client(), request.address, actor_shared(this, actor_id), + "GetAccountState", client_.get_client(), request.address, std::move(request.block_id), + actor_shared(this, actor_id), promise.wrap([address = request.address, wallet_id = wallet_id_](auto&& state) mutable { return td::make_unique(std::move(address), std::move(state), wallet_id); })); return td::Status::OK(); } +td::Status TonlibClient::do_request(int_api::RemoteRunSmcMethod request, + td::Promise&& promise) { + auto actor_id = actor_id_++; + actors_[actor_id] = td::actor::create_actor( + "RemoteRunSmcMethod", client_.get_client(), std::move(request), actor_shared(this, actor_id), std::move(promise)); + return td::Status::OK(); +} + td::Status TonlibClient::do_request(int_api::GetPrivateKey request, td::Promise&& promise) { TRY_RESULT(pk, key_storage_.load_private_key(std::move(request.input_key))); promise.set_value(std::move(pk)); return td::Status::OK(); } +td::Status TonlibClient::do_request(int_api::GetDnsResolver request, td::Promise&& promise) { + client_.with_last_config(promise.wrap([](auto&& state) mutable -> td::Result { + TRY_RESULT_PREFIX(addr, TRY_VM(state.config->get_dns_root_addr()), + TonlibError::Internal("get dns root addr from config: ")); + return block::StdAddress(ton::masterchainId, addr); + })); + return td::Status::OK(); +} + td::Status TonlibClient::do_request(int_api::SendMessage request, td::Promise&& promise) { client_.send_query(ton::lite_api::liteServer_sendMessage(vm::std_boc_serialize(request.message).move_as_ok()), to_any_promise(std::move(promise))); @@ -2535,33 +3280,31 @@ td::Status TonlibClient::do_request(const tonlib_api::liteServer_getInfo& reques return td::Status::OK(); } +td::Status TonlibClient::do_request(tonlib_api::withBlock& request, + td::Promise>&& promise) { + if (!request.id_) { + return TonlibError::EmptyField("id"); + } + auto to_bits256 = [](td::Slice data, td::Slice name) -> td::Result { + if (data.size() != 32) { + return TonlibError::InvalidField(name, "wrong length (not 32 bytes)"); + } + return td::Bits256(data.ubegin()); + }; + TRY_RESULT(root_hash, to_bits256(request.id_->root_hash_, "root_hash")); + TRY_RESULT(file_hash, to_bits256(request.id_->file_hash_, "file_hash")); + ton::BlockIdExt block_id(request.id_->workchain_, request.id_->shard_, request.id_->seqno_, root_hash, file_hash); + make_any_request(*request.function_, {std::move(block_id)}, std::move(promise)); + return td::Status::OK(); +} + template td::Status TonlibClient::do_request(const tonlib_api::runTests& request, P&&) { UNREACHABLE(); return TonlibError::Internal(); } template -td::Status TonlibClient::do_request(const tonlib_api::raw_getAccountAddress& request, P&&) { - UNREACHABLE(); - return TonlibError::Internal(); -} -template -td::Status TonlibClient::do_request(const tonlib_api::testWallet_getAccountAddress& request, P&&) { - UNREACHABLE(); - return TonlibError::Internal(); -} -template -td::Status TonlibClient::do_request(const tonlib_api::wallet_getAccountAddress& request, P&&) { - UNREACHABLE(); - return TonlibError::Internal(); -} -template -td::Status TonlibClient::do_request(const tonlib_api::wallet_v3_getAccountAddress& request, P&&) { - UNREACHABLE(); - return TonlibError::Internal(); -} -template -td::Status TonlibClient::do_request(const tonlib_api::testGiver_getAccountAddress& request, P&&) { +td::Status TonlibClient::do_request(const tonlib_api::getAccountAddress& request, P&&) { UNREACHABLE(); return TonlibError::Internal(); } @@ -2576,11 +3319,6 @@ td::Status TonlibClient::do_request(const tonlib_api::unpackAccountAddress& requ return TonlibError::Internal(); } template -td::Status TonlibClient::do_request(const tonlib_api::options_validateConfig& request, P&&) { - UNREACHABLE(); - return TonlibError::Internal(); -} -template td::Status TonlibClient::do_request(tonlib_api::getBip39Hints& request, P&&) { UNREACHABLE(); return TonlibError::Internal(); diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/TonlibClient.h b/submodules/ton/tonlib-src/tonlib/tonlib/TonlibClient.h index 68936a4373..786e4e7760 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/TonlibClient.h +++ b/submodules/ton/tonlib-src/tonlib/tonlib/TonlibClient.h @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once @@ -32,13 +32,19 @@ #include "td/utils/CancellationToken.h" #include "td/utils/optional.h" +#include "smc-envelope/ManualDns.h" + #include namespace tonlib { namespace int_api { struct GetAccountState; struct GetPrivateKey; +struct GetDnsResolver; struct SendMessage; +struct RemoteRunSmcMethod; +struct RemoteRunSmcMethodReturnType; + inline std::string to_string(const int_api::SendMessage&) { return "Send message"; } @@ -46,6 +52,10 @@ inline std::string to_string(const int_api::SendMessage&) { class AccountState; class Query; +td::Result> to_tonlib_api( + const ton::ManualDns::EntryData& entry_data); +td::Result to_dns_entry_data(tonlib_api::dns_EntryData& entry_data); + class TonlibClient : public td::actor::Actor { public: template @@ -58,6 +68,14 @@ class TonlibClient : public td::actor::Actor { ~TonlibClient(); + struct FullConfig { + Config config; + bool use_callbacks_for_network; + LastBlockState last_state; + std::string last_state_key; + td::uint32 wallet_id; + }; + private: enum class State { Uninited, Running, Closed } state_ = State::Uninited; td::unique_ptr callback_; @@ -66,14 +84,17 @@ class TonlibClient : public td::actor::Actor { Config config_; td::uint32 config_generation_{0}; td::uint32 wallet_id_; - std::string blockchain_name_; - bool ignore_cache_{false}; + std::string last_state_key_; bool use_callbacks_for_network_{false}; // KeyStorage std::shared_ptr kv_; KeyStorage key_storage_; LastBlockStorage last_block_storage_; + struct QueryContext { + td::optional block_id; + }; + QueryContext query_context_; // network td::actor::ActorOwn raw_client_; @@ -89,7 +110,7 @@ class TonlibClient : public td::actor::Actor { ExtClientRef get_client_ref(); void init_ext_client(); - void init_last_block(td::optional o_master_config); + void init_last_block(LastBlockState state); void init_last_config(); bool is_closing_{false}; @@ -121,14 +142,9 @@ class TonlibClient : public td::actor::Actor { return tonlib_api::make_object(400, "Function can't be executed synchronously"); } static object_ptr do_static_request(const tonlib_api::runTests& request); - static object_ptr do_static_request(const tonlib_api::raw_getAccountAddress& request); - static object_ptr do_static_request(const tonlib_api::testWallet_getAccountAddress& request); - static object_ptr do_static_request(const tonlib_api::wallet_getAccountAddress& request); - static object_ptr do_static_request(const tonlib_api::wallet_v3_getAccountAddress& request); - static object_ptr do_static_request(const tonlib_api::testGiver_getAccountAddress& request); + static object_ptr do_static_request(const tonlib_api::getAccountAddress& request); static object_ptr do_static_request(const tonlib_api::packAccountAddress& request); static object_ptr do_static_request(const tonlib_api::unpackAccountAddress& request); - static object_ptr do_static_request(tonlib_api::options_validateConfig& request); static object_ptr do_static_request(tonlib_api::getBip39Hints& request); static object_ptr do_static_request(tonlib_api::setLogStream& request); @@ -147,22 +163,12 @@ class TonlibClient : public td::actor::Actor { template td::Status do_request(const tonlib_api::runTests& request, P&&); template - td::Status do_request(const tonlib_api::raw_getAccountAddress& request, P&&); - template - td::Status do_request(const tonlib_api::testWallet_getAccountAddress& request, P&&); - template - td::Status do_request(const tonlib_api::wallet_getAccountAddress& request, P&&); - template - td::Status do_request(const tonlib_api::wallet_v3_getAccountAddress& request, P&&); - template - td::Status do_request(const tonlib_api::testGiver_getAccountAddress& request, P&&); + td::Status do_request(const tonlib_api::getAccountAddress& request, P&&); template td::Status do_request(const tonlib_api::packAccountAddress& request, P&&); template td::Status do_request(const tonlib_api::unpackAccountAddress& request, P&&); template - td::Status do_request(const tonlib_api::options_validateConfig& request, P&&); - template td::Status do_request(tonlib_api::getBip39Hints& request, P&&); template @@ -189,26 +195,26 @@ class TonlibClient : public td::actor::Actor { template td::Status do_request(const tonlib_api::kdf& request, P&&); + void make_any_request(tonlib_api::Function& function, QueryContext query_context, + td::Promise>&& promise); template void make_request(T&& request, P&& promise) { - auto status = do_request(std::forward(request), std::move(promise)); + td::Promise::ReturnType> new_promise = std::move(promise); + + auto status = do_request(std::forward(request), std::move(new_promise)); if (status.is_error()) { - promise.operator()(std::move(status)); + new_promise.operator()(std::move(status)); } } - struct FullConfig { - Config config; - td::optional o_master_config; - bool use_callbacks_for_network; - bool ignore_cache; - td::uint32 wallet_id; - }; - static td::Result validate_config(tonlib_api::object_ptr config); + td::Result validate_config(tonlib_api::object_ptr config); void set_config(FullConfig config); - td::Status do_request(const tonlib_api::init& request, td::Promise>&& promise); + td::Status do_request(const tonlib_api::init& request, td::Promise>&& promise); td::Status do_request(const tonlib_api::close& request, td::Promise>&& promise); - td::Status do_request(tonlib_api::options_setConfig& request, td::Promise>&& promise); + td::Status do_request(tonlib_api::options_validateConfig& request, + td::Promise>&& promise); + td::Status do_request(tonlib_api::options_setConfig& request, + td::Promise>&& promise); td::Status do_request(const tonlib_api::raw_sendMessage& request, td::Promise>&& promise); td::Status do_request(const tonlib_api::raw_createAndSendMessage& request, @@ -217,33 +223,16 @@ class TonlibClient : public td::actor::Actor { td::Promise>&& promise); td::Status do_request(tonlib_api::raw_getAccountState& request, - td::Promise>&& promise); + td::Promise>&& promise); td::Status do_request(tonlib_api::raw_getTransactions& request, td::Promise>&& promise); - td::Status do_request(const tonlib_api::testWallet_init& request, td::Promise>&& promise); - td::Status do_request(const tonlib_api::testWallet_sendGrams& request, - td::Promise>&& promise); - td::Status do_request(tonlib_api::testWallet_getAccountState& request, - td::Promise>&& promise); + td::Status do_request(const tonlib_api::getAccountState& request, + td::Promise>&& promise); + td::Status do_request(const tonlib_api::guessAccountRevision& request, + td::Promise>&& promise); - td::Status do_request(const tonlib_api::wallet_init& request, td::Promise>&& promise); - td::Status do_request(const tonlib_api::wallet_sendGrams& request, - td::Promise>&& promise); - td::Status do_request(tonlib_api::wallet_getAccountState& request, - td::Promise>&& promise); - - td::Status do_request(const tonlib_api::testGiver_getAccountState& request, - td::Promise>&& promise); - td::Status do_request(const tonlib_api::testGiver_sendGrams& request, - td::Promise>&& promise); - - td::Status do_request(const tonlib_api::generic_getAccountState& request, - td::Promise>&& promise); - td::Status do_request(tonlib_api::generic_sendGrams& request, - td::Promise>&& promise); - - td::Status do_request(tonlib_api::sync& request, td::Promise>&& promise); + td::Status do_request(tonlib_api::sync& request, td::Promise>&& promise); td::Status do_request(const tonlib_api::createNewKey& request, td::Promise>&& promise); td::Status do_request(const tonlib_api::exportKey& request, @@ -261,6 +250,11 @@ class TonlibClient : public td::actor::Actor { td::Status do_request(const tonlib_api::importEncryptedKey& request, td::Promise>&& promise); + td::Status do_request(const tonlib_api::exportUnencryptedKey& request, + td::Promise>&& promise); + td::Status do_request(const tonlib_api::importUnencryptedKey& request, + td::Promise>&& promise); + td::Status do_request(const tonlib_api::changeLocalPassword& request, td::Promise>&& promise); @@ -275,8 +269,6 @@ class TonlibClient : public td::actor::Actor { td::Result> get_query_info(td::int64 id); void finish_create_query(td::Result> r_query, td::Promise>&& promise); - void finish_send_query(td::Result> r_query, - td::Promise>&& promise); void query_estimate_fees(td::int64 id, bool ignore_chksig, td::Result r_state, td::Promise>&& promise); @@ -287,8 +279,9 @@ class TonlibClient : public td::actor::Actor { td::Status do_request(const tonlib_api::query_send& request, td::Promise>&& promise); td::Status do_request(tonlib_api::query_forget& request, td::Promise>&& promise); - td::Status do_request(tonlib_api::generic_createSendGramsQuery& request, - td::Promise>&& promise); + td::Status do_request(tonlib_api::createQuery& request, td::Promise>&& promise); + + td::Status do_request(tonlib_api::msg_decrypt& request, td::Promise>&& promise); td::int64 next_smc_id_{0}; std::map> smcs_; @@ -307,13 +300,29 @@ class TonlibClient : public td::actor::Actor { td::Status do_request(const tonlib_api::smc_runGetMethod& request, td::Promise>&& promise); + td::Status do_request(const tonlib_api::dns_resolve& request, + td::Promise>&& promise); + void do_dns_request(std::string name, td::int32 category, td::int32 ttl, td::optional block_id, + block::StdAddress address, td::Promise>&& promise); + struct DnsFinishData { + ton::BlockIdExt block_id; + ton::SmartContract::State smc_state; + }; + void finish_dns_resolve(std::string name, td::int32 category, td::int32 ttl, td::optional block_id, + DnsFinishData dns_finish_data, td::Promise>&& promise); + td::Status do_request(int_api::GetAccountState request, td::Promise>&&); td::Status do_request(int_api::GetPrivateKey request, td::Promise&&); + td::Status do_request(int_api::GetDnsResolver request, td::Promise&&); + td::Status do_request(int_api::RemoteRunSmcMethod request, + td::Promise&& promise); td::Status do_request(int_api::SendMessage request, td::Promise&& promise); td::Status do_request(const tonlib_api::liteServer_getInfo& request, td::Promise>&& promise); + td::Status do_request(tonlib_api::withBlock& request, td::Promise>&& promise); + void proxy_request(td::int64 query_id, std::string data); friend class TonlibQueryActor; diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/TonlibError.h b/submodules/ton/tonlib-src/tonlib/tonlib/TonlibError.h index dca5eecfcb..a1d98fb3bb 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/TonlibError.h +++ b/submodules/ton/tonlib-src/tonlib/tonlib/TonlibError.h @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once @@ -32,6 +32,7 @@ // INVALID_ACCOUNT_ADDRESS // INVALID_CONFIG // INVALID_PEM_KEY +// INVALID_REVISION // MESSAGE_TOO_LONG // EMPTY_FIELD // INVALID_FIELD @@ -39,6 +40,7 @@ // ACCOUNT_NOT_INITED // ACCOUNT_TYPE_UNKNOWN // ACCOUNT_TYPE_UNEXPECTED +// ACCOUNT_ACTION_UNSUPPORTED // VALIDATE_ACCOUNT_STATE // VALIDATE_TRANSACTION // VALIDATE_ZERO_STATE @@ -79,6 +81,9 @@ struct TonlibError { static td::Status InvalidPemKey() { return td::Status::Error(400, "INVALID_PEM_KEY"); } + static td::Status InvalidRevision() { + return td::Status::Error(400, "INVALID_REVISION"); + } static td::Status NeedConfig() { return td::Status::Error(400, "NeedConfig"); } @@ -86,7 +91,7 @@ struct TonlibError { return td::Status::Error(400, "MESSAGE_TOO_LONG"); } static td::Status EmptyField(td::Slice field_name) { - return td::Status::Error(400, PSLICE() << "EMPTY_FIELD: Field " << field_name << " must not be emtpy"); + return td::Status::Error(400, PSLICE() << "EMPTY_FIELD: Field " << field_name << " must not be empty"); } static td::Status InvalidField(td::Slice field_name, td::Slice reason) { return td::Status::Error(400, PSLICE() << "INVALID_FIELD: Field " << field_name << " has invalid value " << reason); @@ -94,6 +99,9 @@ struct TonlibError { static td::Status DangerousTransaction(td::Slice reason) { return td::Status::Error(400, PSLICE() << "DANGEROUS_TRANSACTION: " << reason); } + static td::Status MessageEncryption(td::Slice reason) { + return td::Status::Error(400, PSLICE() << "MESSAGE_ENCRYPTION: " << reason); + } static td::Status AccountNotInited() { return td::Status::Error(400, "ACCOUNT_NOT_INITED"); } @@ -103,6 +111,9 @@ struct TonlibError { static td::Status AccountTypeUnexpected(td::Slice expected) { return td::Status::Error(400, PSLICE() << "ACCOUNT_TYPE_UNEXPECTED: not a " << expected); } + static td::Status AccountActionUnsupported(td::Slice action) { + return td::Status::Error(400, PSLICE() << "ACCOUNT_ACTION_UNSUPPORTED: " << action); + } static td::Status Internal() { return td::Status::Error(500, "INTERNAL"); } diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/keys/SimpleEncryption.cpp b/submodules/ton/tonlib-src/tonlib/tonlib/keys/SimpleEncryption.cpp index 586070b090..456abf9968 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/keys/SimpleEncryption.cpp +++ b/submodules/ton/tonlib-src/tonlib/tonlib/keys/SimpleEncryption.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #include "SimpleEncryption.h" @@ -36,8 +36,9 @@ td::AesCbcState SimpleEncryption::calc_aes_cbc_state_sha512(td::Slice seed) { sha512(seed, hash.as_mutable_slice()); return calc_aes_cbc_state_hash(hash.as_slice()); } -td::SecureString SimpleEncryption::gen_random_prefix(td::int64 data_size) { - td::SecureString buff(td::narrow_cast(((32 + 15 + data_size) & -16) - data_size), 0); + +td::SecureString SimpleEncryption::gen_random_prefix(td::int64 data_size, td::int64 min_padding) { + td::SecureString buff(td::narrow_cast(((min_padding + 15 + data_size) & -16) - data_size), 0); td::Random::secure_bytes(buff.as_mutable_slice()); buff.as_mutable_slice()[0] = td::narrow_cast(buff.size()); CHECK((buff.size() + data_size) % 16 == 0); @@ -71,7 +72,7 @@ td::SecureString SimpleEncryption::encrypt_data_with_prefix(td::Slice data, td:: } td::SecureString SimpleEncryption::encrypt_data(td::Slice data, td::Slice secret) { - auto prefix = gen_random_prefix(data.size()); + auto prefix = gen_random_prefix(data.size(), 32); td::SecureString combined(prefix.size() + data.size()); combined.as_mutable_slice().copy_from(prefix); combined.as_mutable_slice().substr(prefix.size()).copy_from(data); @@ -104,4 +105,96 @@ td::Result SimpleEncryption::decrypt_data(td::Slice encrypted_ return td::SecureString(decrypted_data.as_slice().substr(prefix_size)); } + +td::Result SimpleEncryptionV2::encrypt_data(td::Slice data, + const td::Ed25519::PublicKey &public_key) { + TRY_RESULT(tmp_private_key, td::Ed25519::generate_private_key()); + return encrypt_data(data, public_key, tmp_private_key); +} + +namespace { +td::SecureString secure_xor(td::Slice a, td::Slice b) { + CHECK(a.size() == b.size()); + td::SecureString res(a.size()); + for (size_t i = 0; i < res.size(); i++) { + res.as_mutable_slice()[i] = a[i] ^ b[i]; + } + return res; +} +} // namespace + +td::Result SimpleEncryptionV2::encrypt_data(td::Slice data, const td::Ed25519::PublicKey &public_key, + const td::Ed25519::PrivateKey &private_key) { + TRY_RESULT(shared_secret, td::Ed25519::compute_shared_secret(public_key, private_key)); + auto encrypted = encrypt_data(data, shared_secret.as_slice()); + TRY_RESULT(tmp_public_key, private_key.get_public_key()); + td::SecureString prefixed_encrypted(tmp_public_key.LENGTH + encrypted.size()); + prefixed_encrypted.as_mutable_slice().copy_from(tmp_public_key.as_octet_string()); + auto xored_keys = secure_xor(public_key.as_octet_string().as_slice(), tmp_public_key.as_octet_string().as_slice()); + prefixed_encrypted.as_mutable_slice().copy_from(xored_keys.as_slice()); + prefixed_encrypted.as_mutable_slice().substr(xored_keys.size()).copy_from(encrypted); + return std::move(prefixed_encrypted); +} + +td::Result SimpleEncryptionV2::decrypt_data(td::Slice data, + const td::Ed25519::PrivateKey &private_key) { + if (data.size() < td::Ed25519::PublicKey::LENGTH) { + return td::Status::Error("Failed to decrypte: data is too small"); + } + TRY_RESULT(public_key, private_key.get_public_key()); + auto tmp_public_key = + td::Ed25519::PublicKey(secure_xor(data.substr(0, td::Ed25519::PublicKey::LENGTH), public_key.as_octet_string())); + TRY_RESULT(shared_secret, td::Ed25519::compute_shared_secret(tmp_public_key, private_key)); + TRY_RESULT(decrypted, decrypt_data(data.substr(td::Ed25519::PublicKey::LENGTH), shared_secret.as_slice())); + return std::move(decrypted); +} +td::SecureString SimpleEncryptionV2::encrypt_data(td::Slice data, td::Slice secret) { + auto prefix = SimpleEncryption::gen_random_prefix(data.size(), 16); + td::SecureString combined(prefix.size() + data.size()); + combined.as_mutable_slice().copy_from(prefix); + combined.as_mutable_slice().substr(prefix.size()).copy_from(data); + return encrypt_data_with_prefix(combined.as_slice(), secret); +} +td::Result SimpleEncryptionV2::decrypt_data(td::Slice encrypted_data, td::Slice secret) { + if (encrypted_data.size() < 17) { + return td::Status::Error("Failed to decrypt: data is too small"); + } + if (encrypted_data.size() % 16 != 0) { + return td::Status::Error("Failed to decrypt: data size is not divisible by 16"); + } + auto msg_key = encrypted_data.substr(0, 16); + encrypted_data = encrypted_data.substr(16); + + auto cbc_state = SimpleEncryption::calc_aes_cbc_state_hash(SimpleEncryption::combine_secrets(secret, msg_key)); + td::SecureString decrypted_data(encrypted_data.size(), 0); + cbc_state.decrypt(encrypted_data, decrypted_data.as_mutable_slice()); + + auto data_hash = SimpleEncryption::combine_secrets(decrypted_data, secret); + auto got_msg_key = data_hash.as_slice().substr(0, 16); + // check hash + if (msg_key != got_msg_key) { + return td::Status::Error("Failed to decrypt: hash mismatch"); + } + + td::uint8 prefix_size = static_cast(decrypted_data[0]); + if (prefix_size > decrypted_data.size() || prefix_size < 16) { + return td::Status::Error("Failed to decrypt: invalid prefix size"); + } + + return td::SecureString(decrypted_data.as_slice().substr(prefix_size)); +} +td::SecureString SimpleEncryptionV2::encrypt_data_with_prefix(td::Slice data, td::Slice secret) { + CHECK(data.size() % 16 == 0); + auto data_hash = SimpleEncryption::combine_secrets(data, secret); + auto msg_key = data_hash.as_slice().substr(0, 16); + + td::SecureString res_buf(data.size() + 16, 0); + auto res = res_buf.as_mutable_slice(); + res.copy_from(msg_key); + + auto cbc_state = SimpleEncryption::calc_aes_cbc_state_hash(SimpleEncryption::combine_secrets(secret, msg_key)); + cbc_state.encrypt(data, res.substr(16)); + + return res_buf; +} } // namespace tonlib diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/keys/SimpleEncryption.h b/submodules/ton/tonlib-src/tonlib/tonlib/keys/SimpleEncryption.h index 69d5629a72..d170c26bce 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/keys/SimpleEncryption.h +++ b/submodules/ton/tonlib-src/tonlib/tonlib/keys/SimpleEncryption.h @@ -14,13 +14,14 @@ You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . - Copyright 2017-2019 Telegram Systems LLP + Copyright 2017-2020 Telegram Systems LLP */ #pragma once #include "td/utils/crypto.h" #include "td/utils/Slice.h" #include "td/utils/SharedSlice.h" +#include "crypto/Ed25519.h" namespace tonlib { class SimpleEncryption { @@ -33,8 +34,23 @@ class SimpleEncryption { private: static td::AesCbcState calc_aes_cbc_state_hash(td::Slice hash); static td::AesCbcState calc_aes_cbc_state_sha512(td::Slice seed); - static td::SecureString gen_random_prefix(td::int64 data_size); + static td::SecureString gen_random_prefix(td::int64 data_size, td::int64 min_padding); static td::SecureString encrypt_data_with_prefix(td::Slice data, td::Slice secret); + + friend class SimpleEncryptionV2; +}; + +class SimpleEncryptionV2 { + public: + static td::Result encrypt_data(td::Slice data, const td::Ed25519::PublicKey &public_key); + static td::Result decrypt_data(td::Slice data, const td::Ed25519::PrivateKey &private_key); + static td::Result encrypt_data(td::Slice data, const td::Ed25519::PublicKey &public_key, + const td::Ed25519::PrivateKey &private_key); + static td::SecureString encrypt_data(td::Slice data, td::Slice secret); + static td::Result decrypt_data(td::Slice encrypted_data, td::Slice secret); + + private: + static td::SecureString encrypt_data_with_prefix(td::Slice data, td::Slice secret); }; } // namespace tonlib diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/tonlib-cli.cpp b/submodules/ton/tonlib-src/tonlib/tonlib/tonlib-cli.cpp index 716fae3070..2f37df6851 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/tonlib-cli.cpp +++ b/submodules/ton/tonlib-src/tonlib/tonlib/tonlib-cli.cpp @@ -1,7 +1,35 @@ +/* + This file is part of TON Blockchain source code. + + TON Blockchain is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + TON Blockchain is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TON Blockchain. If not, see . + + In addition, as a special exception, the copyright holders give permission + to link the code of portions of this program with the OpenSSL library. + You must obey the GNU General Public License in all respects for all + of the code used other than OpenSSL. If you modify file(s) with this + exception, you may extend this exception to your version of the file(s), + but you are not obligated to do so. If you do not wish to do so, delete this + exception statement from your version. If you delete this exception statement + from all source files in the program, then also delete it here. + + Copyright 2019-2020 Telegram Systems LLP +*/ #include "td/actor/actor.h" #include "td/utils/filesystem.h" #include "td/utils/OptionsParser.h" +#include "td/utils/overloaded.h" #include "td/utils/Parser.h" #include "td/utils/port/signals.h" #include "td/utils/port/path.h" @@ -15,62 +43,65 @@ #include "tonlib/ExtClientLazy.h" +#include "smc-envelope/ManualDns.h" + #include "auto/tl/tonlib_api.hpp" +#include #include #include -// Consider this as a TODO list: -// -// (from lite-client) -// SUPPORTED -// "time\tGet server time\n" -// "remote-version\tShows server time, version and capabilities\n" -// "help []\tThis help\n" // TODO: support [] -// "quit\tExit\n"; -// "sendfile \tLoad a serialized message from and send it to server\n" -// "saveaccount[code|data] []\tSaves into specified file the most recent state " -// "(StateInit) or just the code or data of specified account; is in " -// "[:] format\n" -// -// "runmethod ...\tRuns GET method of account " -// "with specified parameters\n" -// -// "getaccount []\tLoads the most recent state of specified account; is in " -// "[:] format\n" -// -// WONTSUPPORT -// -// UNSUPPORTED -//"last\tGet last block and state info from server\n" -//"status\tShow connection and local database status\n" -//"allshards []\tShows shard configuration from the most recent masterchain " -//"state or from masterchain state corresponding to \n" -//"getconfig [...]\tShows specified or all configuration parameters from the latest masterchain state\n" -//"getconfigfrom [...]\tShows specified or all configuration parameters from the " -//"masterchain state of \n" -//"saveconfig []\tSaves all configuration parameters into specified file\n" -//"gethead \tShows block header for \n" -//"getblock \tDownloads block\n" -//"dumpblock \tDownloads and dumps specified block\n" -//"getstate \tDownloads state corresponding to specified block\n" -//"dumpstate \tDownloads and dumps state corresponding to specified block\n" -//"dumptrans \tDumps one transaction of specified account\n" -//"lasttrans[dump] []\tShows or dumps specified transaction and " -//"several preceding " -//"ones\n" -//"listblocktrans[rev] [ ]\tLists block transactions, " -//"starting immediately after or before the specified one\n" -//"blkproofchain[step] []\tDownloads and checks proof of validity of the /"second " -//"indicated block (or the last known masterchain block) starting from given block\n" -//"byseqno \tLooks up a block by workchain, shard and seqno, and shows its " -//"header\n" -//"bylt \tLooks up a block by workchain, shard and logical time, and shows its " -//"header\n" -//"byutime \tLooks up a block by workchain, shard and creation time, and " -//"shows its header\n" -//"known\tShows the list of all known block ids\n" -//"privkey \tLoads a private key from file\n" +// GR$ +struct Grams { + td::uint64 nano; +}; + +td::StringBuilder& operator<<(td::StringBuilder& sb, const Grams& grams) { + auto b = grams.nano % 1000000000; + auto a = grams.nano / 1000000000; + sb << "GR$" << a; + if (b != 0) { + size_t sz = 9; + while (b % 10 == 0) { + sz--; + b /= 10; + } + sb << '.'; + [&](auto b_str) { + for (size_t i = b_str.size(); i < sz; i++) { + sb << '0'; + } + sb << b_str; + }(PSLICE() << b); + } + return sb; +} + +td::Result parse_grams(td::Slice grams) { + td::ConstParser parser(grams); + if (parser.skip_start_with("GR$")) { + TRY_RESULT(a, td::to_integer_safe(parser.read_till_nofail('.'))); + td::uint64 res = a; + if (parser.try_skip('.')) { + for (int i = 0; i < 9; i++) { + res *= 10; + if (parser.peek_char() >= '0' && parser.peek_char() <= '9') { + res += parser.peek_char() - '0'; + parser.advance(1); + } + } + } else { + res *= 1000000000; + } + if (!parser.empty()) { + return td::Status::Error(PSLICE() << "Failed to parse grams \"" << grams << "\", left \"" << parser.read_all() + << "\""); + } + return Grams{res}; + } + TRY_RESULT(value, td::to_integer_safe(grams)); + return Grams{value}; +} class TonlibCli : public td::actor::Actor { public: @@ -82,6 +113,8 @@ class TonlibCli : public td::actor::Actor { bool in_memory{false}; bool use_callbacks_for_network{false}; td::int32 wallet_version = 2; + td::int32 wallet_revision = 0; + td::optional wallet_id; bool ignore_cache{false}; bool one_shot{false}; @@ -97,6 +130,8 @@ class TonlibCli : public td::actor::Actor { std::uint64_t next_query_id_{1}; td::Promise cont_; td::uint32 wallet_id_; + ton::tonlib_api::object_ptr current_block_; + enum class BlockMode { Auto, Manual } block_mode_ = BlockMode::Auto; struct KeyInfo { std::string public_key; @@ -177,10 +212,6 @@ class TonlibCli : public td::actor::Actor { ? make_object(options_.config, options_.name, options_.use_callbacks_for_network, options_.ignore_cache) : nullptr; - auto config2 = !options_.config.empty() - ? make_object(options_.config, options_.name, - options_.use_callbacks_for_network, options_.ignore_cache) - : nullptr; tonlib_api::object_ptr ks_type; if (options_.in_memory) { @@ -188,22 +219,23 @@ class TonlibCli : public td::actor::Actor { } else { ks_type = make_object(options_.key_dir); } - auto obj = - tonlib::TonlibClient::static_request(make_object(std::move(config2))); - if (obj->get_id() != tonlib_api::error::ID) { - auto info = ton::move_tl_object_as(obj); - wallet_id_ = static_cast(info->default_wallet_id_); - } else { - LOG(ERROR) << "Invalid config"; - } send_query(make_object(make_object(std::move(config), std::move(ks_type))), - [](auto r_ok) { + [&](auto r_ok) { LOG_IF(ERROR, r_ok.is_error()) << r_ok.error(); - td::TerminalIO::out() << "Tonlib is inited\n"; + if (r_ok.is_ok()) { + if (r_ok.ok()->config_info_) { + if (options_.wallet_id) { + wallet_id_ = options_.wallet_id.value(); + } else { + wallet_id_ = static_cast(r_ok.ok()->config_info_->default_wallet_id_); + } + } + td::TerminalIO::out() << "Tonlib is inited\n"; + if (options_.one_shot) { + td::actor::send_closure(actor_id(this), &TonlibCli::parse_line, td::BufferSlice(options_.cmd)); + } + } }); - if (options_.one_shot) { - td::actor::send_closure(actor_id(this), &TonlibCli::parse_line, td::BufferSlice(options_.cmd)); - } } void hangup_shared() override { @@ -230,19 +262,6 @@ class TonlibCli : public td::actor::Actor { } } - void on_error() { - if (options_.one_shot) { - LOG(ERROR) << "FAILED"; - std::_Exit(1); - } - } - void on_ok() { - if (options_.one_shot) { - LOG(INFO) << "OK"; - std::_Exit(0); - } - } - void parse_line(td::BufferSlice line) { if (is_closing_) { return; @@ -267,11 +286,18 @@ class TonlibCli : public td::actor::Actor { return true; }; - td::Promise cmd_promise = [line = line.clone()](td::Result res) { + td::Promise cmd_promise = [line = line.clone(), one_shot = options_.one_shot](td::Result res) { if (res.is_ok()) { - // on_ok + if (one_shot) { + LOG(DEBUG) << "OK"; + std::_Exit(0); + } } else { td::TerminalIO::out() << "Query {" << line.as_slice() << "} FAILED: \n\t" << res.error() << "\n"; + if (one_shot) { + LOG(ERROR) << "FAILED"; + std::_Exit(1); + } } }; @@ -282,6 +308,25 @@ class TonlibCli : public td::actor::Actor { td::TerminalIO::out() << "sendfile \tLoad a serialized message from and send it to server\n"; td::TerminalIO::out() << "setconfig|validateconfig [] [] [] - set or validate " "lite server config\n"; + td::TerminalIO::out() << "runmethod ...\tRuns GET method of account " + " with specified parameters\n"; + td::TerminalIO::out() << "getstate \tget state of wallet with requested key\n"; + td::TerminalIO::out() << "guessrevision \tsearch of existing accounts corresponding to the given key\n"; + td::TerminalIO::out() << "getaddress \tget address of wallet with requested key\n"; + td::TerminalIO::out() << "dns resolve ( | root) \n"; + td::TerminalIO::out() << "dns cmd \n"; + //td::TerminalIO::out() << "dns cmdlist {\\n} end\n"; + td::TerminalIO::out() << "dns cmdfile \n"; + td::TerminalIO::out() << "\t = set | delete.name | delete.all\n"; + td::TerminalIO::out() << "\t = DELETED | EMPTY | TEXT: | NEXT: | SMC: | " + "ADNL:\n"; + + td::TerminalIO::out() + << "blockmode auto|manual\tWith auto mode, all queries will be executed with respect to the latest block. " + "With manual mode, user must update current block explicitly: with last or setblock\n"; + td::TerminalIO::out() << "last\tUpdate current block to the most recent one\n"; + td::TerminalIO::out() << "setblock \tSet current block\n"; + td::TerminalIO::out() << "exit\tExit\n"; td::TerminalIO::out() << "quit\tExit\n"; td::TerminalIO::out() @@ -292,17 +337,22 @@ class TonlibCli : public td::actor::Actor { td::TerminalIO::out() << "unpackaddress
    - validate and parse address\n"; td::TerminalIO::out() << "setbounceble
    [] - change bounceble flag in address\n"; td::TerminalIO::out() << "importkey - import key\n"; + td::TerminalIO::out() << "importkeypem - import key\n"; + td::TerminalIO::out() << "importkeyraw - import key\n"; td::TerminalIO::out() << "deletekeys - delete ALL PRIVATE KEYS\n"; td::TerminalIO::out() << "exportkey [] - export key\n"; td::TerminalIO::out() << "exportkeypem [] - export key\n"; - td::TerminalIO::out() << "getstate - get state of simple wallet with requested key\n"; td::TerminalIO::out() << "gethistory - get history fo simple wallet with requested key (last 10 transactions)\n"; td::TerminalIO::out() << "init - init simple wallet with requested key\n"; - td::TerminalIO::out() << "transfer[f] - transfer of grams from " - " to .\n" - << "\t could also be 'giver'\n" - << "\t could also be 'giver' or smartcontract address\n"; + td::TerminalIO::out() << "transfer[f][F][e][k][c] ( |) - " + "make transfer from \n" + << "\t 'f' modifier - allow send to uninited account\n" + << "\t 'F' modifier - read list of messages from (in same format " + " , one per line)\n" + << "\t 'e' modifier - encrypt all messages\n" + << "\t 'k' modifier - use fake key\n" + << "\t 'c' modifier - just esmitate fees\n"; } else if (cmd == "genkey") { generate_key(); } else if (cmd == "exit" || cmd == "quit") { @@ -320,18 +370,6 @@ class TonlibCli : public td::actor::Actor { export_key(cmd.str(), parser.read_word()); } else if (cmd == "importkey") { import_key(parser.read_all()); - } else if (cmd == "getstate") { - get_state(parser.read_word()); - } else if (cmd == "gethistory") { - get_history(parser.read_word()); - } else if (cmd == "init") { - init_simple_wallet(parser.read_word()); - } else if (cmd == "transfer" || cmd == "transferf") { - auto from = parser.read_word(); - auto to = parser.read_word(); - auto grams = parser.read_word(); - auto message = parser.read_word(); - transfer(from, to, grams, message, cmd == "transferf"); } else if (cmd == "hint") { get_hints(parser.read_word()); } else if (cmd == "unpackaddress") { @@ -343,8 +381,10 @@ class TonlibCli : public td::actor::Actor { } else if (cmd == "netstats") { dump_netstats(); // reviewed from here - } else if (cmd == "sync") { - sync(std::move(cmd_promise)); + } else if (cmd == "blockmode") { + set_block_mode(parser.read_word(), std::move(cmd_promise)); + } else if (cmd == "sync" || cmd == "last") { + sync(std::move(cmd_promise), cmd == "last"); } else if (cmd == "time") { remote_time(std::move(cmd_promise)); } else if (cmd == "remote-version") { @@ -363,6 +403,26 @@ class TonlibCli : public td::actor::Actor { auto use_callback = parser.read_word(); auto force = parser.read_word(); set_validate_config(cmd, config, name, to_bool(use_callback), to_bool(force), std::move(cmd_promise)); + } else if (td::begins_with(cmd, "transfer") || cmd == "init") { + // transfer[f][F] + // f - force + // F from file - SEND
    + // use @empty for empty message + transfer(parser, cmd, std::move(cmd_promise)); + } else if (cmd == "getstate") { + get_state(parser.read_word(), std::move(cmd_promise)); + } else if (cmd == "getaddress") { + get_address(parser.read_word(), std::move(cmd_promise)); + } else if (cmd == "importkeypem") { + import_key_pem(parser.read_word(), std::move(cmd_promise)); + } else if (cmd == "importkeyraw") { + import_key_raw(parser.read_word(), std::move(cmd_promise)); + } else if (cmd == "dns") { + run_dns_cmd(parser, std::move(cmd_promise)); + } else if (cmd == "gethistory") { + get_history(parser.read_word(), std::move(cmd_promise)); + } else if (cmd == "guessrevision") { + guess_revision(parser.read_word(), std::move(cmd_promise)); } else { cmd_promise.set_error(td::Status::Error(PSLICE() << "Unkwnown query `" << cmd << "`")); } @@ -371,6 +431,109 @@ class TonlibCli : public td::actor::Actor { } } + void run_dns_cmd(td::ConstParser& parser, td::Promise promise) { + auto cmd = parser.read_word(); + if (cmd == "cmd" || cmd == "cmdlist" || cmd == "cmdfile") { + return dns_cmd(cmd, parser, std::move(promise)); + } + if (cmd == "resolve") { + return dns_resolve(parser, std::move(promise)); + } + promise.set_error(td::Status::Error("Unknown cmd")); + } + + void do_dns_resolve(std::string name, td::int16 category, td::int32 ttl, + tonlib_api::object_ptr resolved, td::Promise promise) { + if (resolved->entries_.empty()) { + td::TerminalIO::out() << "No dns entries found\n"; + promise.set_value(td::Unit()); + return; + } + if (resolved->entries_[0]->entry_->get_id() == tonlib_api::dns_entryDataNextResolver::ID && ttl != 0) { + td::TerminalIO::out() << "Redirect resolver\n"; + auto entry = tonlib_api::move_object_as(resolved->entries_[0]->entry_); + send_query(tonlib_api::make_object(std::move(entry->resolver_), name, category, ttl), + promise.send_closure(actor_id(this), &TonlibCli::do_dns_resolve, name, category, 0)); + return; + } + td::TerminalIO::out() << "Done\n"; + for (auto& entry : resolved->entries_) { + td::TerminalIO::out() << " " << entry->name_ << " " << entry->category_ << " " + << tonlib::to_dns_entry_data(*entry->entry_).move_as_ok() << "\n"; + } + promise.set_value(td::Unit()); + } + + void dns_resolve(td::ConstParser& parser, td::Promise promise) { + auto key_id = parser.read_word(); + if (key_id == "root") { + key_id = "none"; + } + TRY_RESULT_PROMISE(promise, address, to_account_address(key_id, false)); + auto name = parser.read_word(); + auto category_str = parser.read_word(); + TRY_RESULT_PROMISE(promise, category, td::to_integer_safe(category_str)); + + std::vector> entries; + entries.push_back(tonlib_api::make_object( + "", -1, tonlib_api::make_object(std::move(address.address)))); + do_dns_resolve(name.str(), category, 10, tonlib_api::make_object(std::move(entries)), + std::move(promise)); + } + void dns_cmd(td::Slice cmd, td::ConstParser& parser, td::Promise promise) { + auto key_id = parser.read_word(); + TRY_RESULT_PROMISE(promise, address, to_account_address(key_id, true)); + + std::vector actions_ext; + if (cmd == "cmd") { + TRY_RESULT_PROMISE_ASSIGN(promise, actions_ext, ton::ManualDns::parse(parser.read_all())); + } else if (cmd == "cmdfile") { + TRY_RESULT_PROMISE(promise, file_data, td::read_file(parser.read_word().str())); + TRY_RESULT_PROMISE_ASSIGN(promise, actions_ext, ton::ManualDns::parse(file_data)); + } + + std::vector> actions; + for (auto& action : actions_ext) { + if (action.name.empty()) { + actions.push_back(tonlib_api::make_object()); + td::TerminalIO::out() << "Delete all dns entries\n"; + } else if (action.category == 0) { + actions.push_back(tonlib_api::make_object(action.name, 0)); + td::TerminalIO::out() << "Delete all dns enties with name: " << action.name << "\n"; + } else if (!action.data) { + actions.push_back(tonlib_api::make_object(action.name, action.category)); + td::TerminalIO::out() << "Delete all dns enties with name and category: " << action.name << ":" + << action.category << "\n"; + } else { + td::StringBuilder sb; + + td::Status error; + if (action.data.value().data.empty()) { + TRY_STATUS_PROMISE(promise, td::Status::Error("Empty entry data is not supported")); + } + TRY_RESULT_PROMISE(promise, data, tonlib::to_tonlib_api(action.data.value())); + sb << action.data.value(); + TRY_STATUS_PROMISE(promise, std::move(error)); + td::TerminalIO::out() << "Set dns entry: " << action.name << ":" << action.category << " " << sb.as_cslice() + << "\n"; + actions.push_back(tonlib_api::make_object( + tonlib_api::make_object(action.name, action.category, std::move(data)))); + } + } + + auto action = tonlib_api::make_object(std::move(actions)); + + td::Slice password; // empty by default + using tonlib_api::make_object; + auto key = !address.secret.empty() ? make_object( + make_object(address.public_key, address.secret.copy()), + td::SecureString(password)) + : nullptr; + send_query(tonlib_api::make_object(std::move(key), std::move(address.address), 60, + std::move(action)), + promise.send_closure(actor_id(this), &TonlibCli::transfer2, false)); + } + void remote_time(td::Promise promise) { send_query(tonlib_api::make_object(), promise.wrap([](auto&& info) { td::TerminalIO::out() << "Lite server time is: " << info->now_ << "\n"; @@ -429,13 +592,29 @@ class TonlibCli : public td::actor::Actor { promise.set_value(td::Unit()); } - void sync(td::Promise promise) { + void sync(td::Promise promise, bool update_last) { using tonlib_api::make_object; - send_query(make_object(), promise.wrap([](auto&&) { + send_query(make_object(), promise.wrap([&, update_last](auto&& block) { td::TerminalIO::out() << "synchronized\n"; + td::TerminalIO::out() << to_string(block) << "\n"; + if (update_last) { + current_block_ = std::move(block); + td::TerminalIO::out() << "Update current block\n"; + } return td::Unit(); })); } + void set_block_mode(td::Slice mode, td::Promise promise) { + if (mode == "auto") { + block_mode_ = BlockMode::Auto; + promise.set_value(td::Unit()); + } else if (mode == "manual") { + block_mode_ = BlockMode::Manual; + promise.set_value(td::Unit()); + } else { + promise.set_error(td::Status::Error("Invalid block mode")); + } + } td::Result> parse_stack_entry(td::Slice str) { if (str.empty() || str.size() > 65535) { return td::Status::Error("String is or empty or too big"); @@ -482,6 +661,73 @@ class TonlibCli : public td::actor::Actor { tonlib_api::make_object(dec_string(num))); } + td::Result>> parse_stack(td::ConstParser& parser, + td::Slice end_token) { + std::vector> stack; + while (true) { + auto word = parser.read_word(); + LOG(ERROR) << word << " vs " << end_token; + if (word == end_token) { + break; + } + if (word == "[") { + TRY_RESULT(elements, parse_stack(parser, "]")); + stack.push_back(tonlib_api::make_object( + tonlib_api::make_object(std::move(elements)))); + } else if (word == "(") { + TRY_RESULT(elements, parse_stack(parser, ")")); + stack.push_back(tonlib_api::make_object( + tonlib_api::make_object(std::move(elements)))); + } else { + TRY_RESULT(stack_entry, parse_stack_entry(word)); + stack.push_back(std::move(stack_entry)); + } + } + return std::move(stack); + } + + static void store_entry(td::StringBuilder& sb, tonlib_api::tvm_StackEntry& entry) { + downcast_call(entry, td::overloaded( + [&](tonlib_api::tvm_stackEntryCell& cell) { + auto r_cell = vm::std_boc_deserialize(cell.cell_->bytes_); + if (r_cell.is_error()) { + sb << ""; + } + auto cs = vm::load_cell_slice(r_cell.move_as_ok()); + std::stringstream ss; + cs.print_rec(ss); + sb << ss.str(); + }, + [&](tonlib_api::tvm_stackEntrySlice& cell) { + auto r_cell = vm::std_boc_deserialize(cell.slice_->bytes_); + if (r_cell.is_error()) { + sb << ""; + } + auto cs = vm::load_cell_slice(r_cell.move_as_ok()); + std::stringstream ss; + cs.print_rec(ss); + sb << ss.str(); + }, + [&](tonlib_api::tvm_stackEntryNumber& cell) { sb << cell.number_->number_; }, + [&](tonlib_api::tvm_stackEntryTuple& cell) { + sb << "("; + for (auto& element : cell.tuple_->elements_) { + sb << " "; + store_entry(sb, *element); + } + sb << " )"; + }, + [&](tonlib_api::tvm_stackEntryList& cell) { + sb << "["; + for (auto& element : cell.list_->elements_) { + sb << " "; + store_entry(sb, *element); + } + sb << " ]"; + }, + [&](tonlib_api::tvm_stackEntryUnsupported& cell) { sb << ""; })); + } + void run_method(td::ConstParser& parser, td::Promise promise) { TRY_RESULT_PROMISE(promise, addr, to_account_address(parser.read_word(), false)); @@ -492,15 +738,15 @@ class TonlibCli : public td::actor::Actor { } else { method = tonlib_api::make_object(method_str.str()); } - std::vector> stack; - while (true) { - auto word = parser.read_word(); - if (word.empty()) { - break; - } - TRY_RESULT_PROMISE(promise, stack_entry, parse_stack_entry(word)); - stack.push_back(std::move(stack_entry)); + TRY_RESULT_PROMISE(promise, stack, parse_stack(parser, "")); + td::StringBuilder sb; + for (auto& entry : stack) { + store_entry(sb, *entry); + sb << "\n"; } + + td::TerminalIO::out() << "Run " << to_string(method) << "With stack:\n" << sb.as_cslice(); + auto to_run = tonlib_api::make_object(0 /*fixme*/, std::move(method), std::move(stack)); @@ -513,9 +759,16 @@ class TonlibCli : public td::actor::Actor { to_run->id_ = info->id_; send_query(std::move(to_run), promise.send_closure(actor_id(this), &TonlibCli::run_method_3)); } - void run_method_3(tonlib_api::object_ptr info, td::Promise promise) { - td::TerminalIO::out() << "Got smc result " << to_string(info); + td::StringBuilder sb; + for (auto& entry : info->stack_) { + store_entry(sb, *entry); + sb << "\n"; + } + + td::TerminalIO::out() << "Got smc result. exit code: " << info->exit_code_ << ", gas_used: " << info->gas_used_ + << "\n" + << sb.as_cslice(); promise.set_value({}); } @@ -625,8 +878,20 @@ class TonlibCli : public td::actor::Actor { if (is_closing_) { return; } + tonlib_api::object_ptr func = std::move(query); + if (block_mode_ == BlockMode::Manual && func->get_id() != tonlib_api::sync::ID) { + if (!current_block_) { + promise.set_error(td::Status::Error("empty current block")); + return; + } + func = tonlib_api::make_object( + tonlib_api::make_object(current_block_->workchain_, current_block_->shard_, + current_block_->seqno_, current_block_->root_hash_, + current_block_->file_hash_), + std::move(func)); + } auto query_id = next_query_id_++; - td::actor::send_closure(client_, &tonlib::TonlibClient::request, query_id, std::move(query)); + td::actor::send_closure(client_, &tonlib::TonlibClient::request, query_id, std::move(func)); query_handlers_[query_id] = [promise = std::move(promise)](td::Result> r_obj) mutable { if (r_obj.is_error()) { @@ -742,7 +1007,6 @@ class TonlibCli : public td::actor::Actor { KeyInfo info; info.public_key = public_key; info.secret = r_secret.move_as_ok(); - LOG(INFO) << info.public_key; keys_.push_back(std::move(info)); } @@ -830,26 +1094,44 @@ class TonlibCli : public td::actor::Actor { td::SecureString secret; }; + template + auto with_account_state(int version, std::string public_key, td::uint32 wallet_id, F&& f) { + using tonlib_api::make_object; + if (version == 1) { + return f(make_object(public_key)); + } + if (version == 2) { + return f(make_object(public_key)); + } + if (version == 4) { + return f(make_object(public_key, wallet_id)); + } + if (version == 5) { + return f(make_object(public_key, wallet_id)); + } + if (version == 6) { + return f(make_object(public_key, wallet_id)); + } + return f(make_object(public_key, wallet_id)); + } + td::Result
    to_account_address(td::Slice key, bool need_private_key) { if (key.empty()) { return td::Status::Error("account address is empty"); } + if (key == "none" && !need_private_key) { + return Address{}; + } auto r_key_i = to_key_i(key); using tonlib_api::make_object; if (r_key_i.is_ok()) { - auto obj = [&](td::int32 version) { - if (version == 1) { - return tonlib::TonlibClient::static_request(make_object( - make_object(keys_[r_key_i.ok()].public_key))); - } - if (version == 2) { - return tonlib::TonlibClient::static_request(make_object( - make_object(keys_[r_key_i.ok()].public_key))); - } - return tonlib::TonlibClient::static_request(make_object( - make_object(keys_[r_key_i.ok()].public_key, wallet_id_))); - UNREACHABLE(); - }(options_.wallet_version); + auto obj = [&](td::int32 version, td::int32 revision) { + auto do_request = [revision](auto x) { + return tonlib::TonlibClient::static_request( + make_object(std::move(x), revision)); + }; + return with_account_state(version, keys_[r_key_i.ok()].public_key, wallet_id_, do_request); + }(options_.wallet_version, options_.wallet_revision); if (obj->get_id() != tonlib_api::error::ID) { Address res; res.address = ton::move_tl_object_as(obj); @@ -859,7 +1141,8 @@ class TonlibCli : public td::actor::Actor { } } if (key == "giver") { - auto obj = tonlib::TonlibClient::static_request(make_object()); + auto obj = tonlib::TonlibClient::static_request( + make_object(make_object(), 0)); if (obj->get_id() != tonlib_api::error::ID) { Address res; res.address = ton::move_tl_object_as(obj); @@ -917,6 +1200,39 @@ class TonlibCli : public td::actor::Actor { cont_ = [this, cmd, key = key.str(), key_i](td::Slice password) { this->export_key(cmd, key, key_i, password); }; } + void import_key_pem(td::Slice filename, td::Promise promise) { + TRY_RESULT_PROMISE(promise, data, td::read_file_secure(filename.str())); + using tonlib_api::make_object; + send_query(make_object(td::SecureString(), td::SecureString("cucumber"), + make_object(std::move(data))), + promise.wrap([&](auto&& key) { + LOG(ERROR) << to_string(key); + KeyInfo info; + info.public_key = key->public_key_; + info.secret = std::move(key->secret_); + keys_.push_back(std::move(info)); + export_key("exportkey", key->public_key_, keys_.size() - 1, td::SecureString()); + store_keys(); + return td::Unit(); + })); + } + void import_key_raw(td::Slice filename, td::Promise promise) { + TRY_RESULT_PROMISE(promise, data, td::read_file_secure(filename.str())); + using tonlib_api::make_object; + send_query(make_object( + td::SecureString(), make_object(std::move(data))), + promise.wrap([&](auto&& key) { + LOG(ERROR) << to_string(key); + KeyInfo info; + info.public_key = key->public_key_; + info.secret = std::move(key->secret_); + keys_.push_back(std::move(info)); + export_key("exportkey", key->public_key_, keys_.size() - 1, td::SecureString()); + store_keys(); + return td::Unit(); + })); + } + void export_key(std::string cmd, std::string key, size_t key_i, td::Slice password) { using tonlib_api::make_object; if (cmd == "exportkey") { @@ -972,7 +1288,7 @@ class TonlibCli : public td::actor::Actor { void import_key(std::vector words, td::Slice password) { using tonlib_api::make_object; - send_query(make_object(td::SecureString(password), td::SecureString(), + send_query(make_object(td::SecureString(password), td::SecureString(""), make_object(std::move(words))), [this, password = td::SecureString(password)](auto r_res) { if (r_res.is_error()) { @@ -990,225 +1306,234 @@ class TonlibCli : public td::actor::Actor { }); } - void get_state(td::Slice key) { - if (key.empty()) { - dump_keys(); - td::TerminalIO::out() << "Choose public key (hex prefix or #N)"; - cont_ = [this](td::Slice key) { this->get_state(key); }; - on_wait(); - return; - } - auto r_address = to_account_address(key, false); - if (r_address.is_error()) { - td::TerminalIO::out() << "Unknown key id: [" << key << "]\n"; - on_error(); - return; - } - auto address = r_address.move_as_ok(); + void get_state(td::Slice key, td::Promise promise) { + TRY_RESULT_PROMISE(promise, address, to_account_address(key, false)); using tonlib_api::make_object; - send_query(make_object( + auto address_str = address.address->account_address_; + send_query(make_object( ton::move_tl_object_as(std::move(address.address))), - [this](auto r_res) { - if (r_res.is_error()) { - td::TerminalIO::out() << "Can't get state: " << r_res.error() << "\n"; - on_error(); - return; - } - td::TerminalIO::out() << to_string(r_res.ok()); - on_ok(); - }); + promise.wrap([address_str](auto&& state) { + td::TerminalIO::out() << "Address: " << address_str << "\n"; + td::TerminalIO::out() << "Balance: " + << Grams{td::narrow_cast(state->balance_ * (state->balance_ > 0))} + << "\n"; + td::TerminalIO::out() << "Sync utime: " << state->sync_utime_ << "\n"; + td::TerminalIO::out() << "transaction.LT: " << state->last_transaction_id_->lt_ << "\n"; + td::TerminalIO::out() << "transaction.Hash: " << td::base64_encode(state->last_transaction_id_->hash_) + << "\n"; + td::TerminalIO::out() << to_string(state->account_state_); + return td::Unit(); + })); } - void get_history(td::Slice key) { - if (key.empty()) { - dump_keys(); - td::TerminalIO::out() << "Choose public key (hex prefix or #N)"; - cont_ = [this](td::Slice key) { this->get_state(key); }; - return; - } - auto r_address = to_account_address(key, false); - if (r_address.is_error()) { - td::TerminalIO::out() << "Unknown key id: [" << key << "]\n"; - return; - } - auto address = r_address.move_as_ok(); + + void get_address(td::Slice key, td::Promise promise) { + TRY_RESULT_PROMISE(promise, address, to_account_address(key, false)); + promise.set_value(td::Unit()); + td::TerminalIO::out() << address.address->account_address_ << "\n"; + } + + void get_history(td::Slice key, td::Promise promise) { + TRY_RESULT_PROMISE(promise, address, to_account_address(key, false)); using tonlib_api::make_object; - send_query(make_object( + send_query(make_object( ton::move_tl_object_as(std::move(address.address))), - [this, key = key.str()](auto r_res) { - if (r_res.is_error()) { - td::TerminalIO::out() << "Can't get state: " << r_res.error() << "\n"; - return; - } - this->get_history(key, *r_res.move_as_ok()); - }); + promise.send_closure(td::actor::actor_id(this), &TonlibCli::get_history2, key.str())); } - void get_history(td::Slice key, tonlib_api::generic_AccountState& state) { - auto r_address = to_account_address(key, false); + void guess_revision(td::Slice key, td::Promise promise) { + TRY_RESULT_PROMISE(promise, key_i, to_key_i(key)); + with_account_state(options_.wallet_version, keys_[key_i].public_key, wallet_id_, [&](auto state) { + using tonlib_api::make_object; + send_query(make_object(std::move(state)), promise.wrap([](auto revisions) { + td::TerminalIO::out() << to_string(revisions); + return td::Unit(); + })); + }); + } + + void get_history2(td::Slice key, td::Result> r_state, + td::Promise promise) { + TRY_RESULT_PROMISE(promise, state, std::move(r_state)); + auto r_address = to_account_address(key, true); if (r_address.is_error()) { - td::TerminalIO::out() << "Unknown key id: [" << key << "]\n"; - return; + r_address = to_account_address(key, false); } - auto address = r_address.move_as_ok(); + TRY_RESULT_PROMISE(promise, address, std::move(r_address)); + td::Slice password; + using tonlib_api::make_object; + auto input_key = + !address.secret.empty() + ? make_object( + make_object(address.public_key, address.secret.copy()), td::SecureString(password)) + : nullptr; - tonlib_api::object_ptr transaction_id; - downcast_call(state, [&](auto& state) { transaction_id = std::move(state.account_state_->last_transaction_id_); }); - - send_query( - tonlib_api::make_object( - ton::move_tl_object_as(std::move(address.address)), std::move(transaction_id)), - [](auto r_res) { - if (r_res.is_error()) { - td::TerminalIO::out() << "Can't get transactions: " << r_res.error() << "\n"; - return; - } - td::TerminalIO::out() << to_string(r_res.move_as_ok()) << "\n"; - }); + send_query(tonlib_api::make_object( + std::move(input_key), ton::move_tl_object_as(std::move(address.address)), + std::move(state->last_transaction_id_)), + promise.wrap([](auto res) { + td::StringBuilder sb; + for (tonlib_api::object_ptr& t : res->transactions_) { + td::int64 balance = 0; + balance += t->in_msg_->value_; + for (auto& ot : t->out_msgs_) { + balance -= ot->value_; + } + if (balance >= 0) { + sb << Grams{td::uint64(balance)}; + } else { + sb << "-" << Grams{td::uint64(-balance)}; + } + sb << " Fee: " << Grams{td::uint64(t->fee_)}; + if (t->in_msg_->source_.empty()) { + sb << " External "; + } else { + sb << " From " << t->in_msg_->source_; + } + auto print_msg_data = [](td::StringBuilder& sb, + tonlib_api::object_ptr& msg_data) { + if (!msg_data) { + return; + } + sb << " "; + downcast_call(*msg_data, + td::overloaded([&](tonlib_api::msg_dataRaw& raw) { sb << ""; }, + [&](tonlib_api::msg_dataText& raw) { sb << "{" << raw.text_ << "}"; }, + [&](tonlib_api::msg_dataEncryptedText& raw) { sb << ""; }, + [&](tonlib_api::msg_dataDecryptedText& raw) { + sb << "decrypted{" << raw.text_ << "}"; + })); + }; + print_msg_data(sb, t->in_msg_->msg_data_); + for (auto& ot : t->out_msgs_) { + sb << "\n\t"; + if (ot->destination_.empty()) { + sb << " External "; + } else { + sb << " To " << ot->destination_; + } + sb << " " << Grams{td::uint64(ot->value_)}; + print_msg_data(sb, ot->msg_data_); + } + sb << "\n"; + } + td::TerminalIO::out() << sb.as_cslice() << "\n"; + return td::Unit(); + })); } - void transfer(td::Slice from, td::Slice to, td::Slice grams, td::Slice message, bool allow_send_to_uninited) { - auto r_from_address = to_account_address(from, true); - if (r_from_address.is_error()) { - td::TerminalIO::out() << "Unknown key id: [" << from << "] : " << r_from_address.error() << "\n"; - on_error(); - return; + void transfer(td::ConstParser& parser, td::Slice cmd, td::Promise cmd_promise) { + bool from_file = false; + bool force = false; + bool use_encryption = false; + bool use_fake_key = false; + bool estimate_fees = false; + if (cmd != "init") { + td::ConstParser cmd_parser(cmd); + cmd_parser.advance(td::Slice("transfer").size()); + while (!cmd_parser.empty()) { + auto c = cmd_parser.peek_char(); + cmd_parser.advance(1); + if (c == 'F') { + from_file = true; + } else if (c == 'f') { + force = true; + } else if (c == 'e') { + use_encryption = true; + } else if (c == 'k') { + use_fake_key = true; + } else if (c == 'c') { + estimate_fees = true; + } else { + cmd_promise.set_error(td::Status::Error(PSLICE() << "Unknown suffix '" << c << "'")); + return; + } + } } - auto r_to_address = to_account_address(to, false); - if (r_to_address.is_error()) { - td::TerminalIO::out() << "Unknown key id: [" << to << "] : " << r_to_address.error() << "\n"; - on_error(); - return; - } - auto r_grams = td::to_integer_safe(grams); - if (r_grams.is_error()) { - td::TerminalIO::out() << "Invalid grams amount: [" << grams << "]\n"; - on_error(); - return; - } - if (options_.one_shot) { - transfer(r_from_address.move_as_ok(), r_to_address.move_as_ok(), r_grams.move_as_ok(), "", "", - allow_send_to_uninited); - return; - } - if (from != "giver" && message.empty()) { - td::TerminalIO::out() << "Enter password (could be empty)"; - cont_ = [this, from = r_from_address.move_as_ok(), to = r_to_address.move_as_ok(), grams = r_grams.move_as_ok(), - allow_send_to_uninited](td::Slice password) mutable { - this->transfer(std::move(from), std::move(to), grams, password, allow_send_to_uninited); - }; - on_wait(); - return; - } - if (message.empty()) { - transfer(r_from_address.move_as_ok(), r_to_address.move_as_ok(), r_grams.move_as_ok(), "", - allow_send_to_uninited); - } else { - transfer(r_from_address.move_as_ok(), r_to_address.move_as_ok(), r_grams.move_as_ok(), "", message, - allow_send_to_uninited); - } - } - void transfer(Address from, Address to, td::uint64 grams, td::Slice password, bool allow_send_to_uninited) { - td::TerminalIO::out() << "Enter message (could be empty)"; - cont_ = [this, from = std::move(from), to = std::move(to), grams, password = password.str(), - allow_send_to_uninited](td::Slice message) mutable { - this->transfer(std::move(from), std::move(to), grams, password, message, allow_send_to_uninited); + auto from = parser.read_word(); + TRY_RESULT_PROMISE(cmd_promise, from_address, to_account_address(from, true)); + + struct Message { + Address to; + td::int64 amount; + std::string message; }; - on_wait(); - return; - } - void transfer(Address from, Address to, td::uint64 grams, td::Slice password, td::Slice message, - bool allow_send_to_uninited) { - auto r_sz = td::to_integer_safe(message); - auto msg = message.str(); - if (r_sz.is_ok()) { - msg = std::string(r_sz.ok(), 'Z'); - } - using tonlib_api::make_object; - auto key = !from.secret.empty() - ? make_object( - make_object(from.public_key, from.secret.copy()), td::SecureString(password)) - : nullptr; - send_query(make_object(std::move(key), std::move(from.address), - std::move(to.address), grams, 60, - allow_send_to_uninited, std::move(msg)), - [self = this](auto r_res) { - if (r_res.is_error()) { - td::TerminalIO::out() << "Can't transfer: " << r_res.error() << "\n"; - self->on_error(); - return; - } - td::TerminalIO::out() << to_string(r_res.ok()); - self->send_query(make_object(r_res.ok()->id_, false), - [self](auto r_res) { - if (r_res.is_error()) { - td::TerminalIO::out() << "Can't transfer: " << r_res.error() << "\n"; - self->on_error(); - return; - } - td::TerminalIO::out() << to_string(r_res.ok()); - self->on_ok(); - }); - self->send_query(make_object(r_res.ok()->id_), [self](auto r_res) { - if (r_res.is_error()) { - td::TerminalIO::out() << "Can't transfer: " << r_res.error() << "\n"; - self->on_error(); - return; - } - td::TerminalIO::out() << to_string(r_res.ok()); - self->on_ok(); - }); + std::vector> messages; + auto add_message = [&](td::ConstParser& parser) { + auto to = parser.read_word(); + auto grams = parser.read_word(); + parser.skip_whitespaces(); + auto message = parser.read_all(); - self->on_ok(); - }); - } + Message res; + TRY_RESULT(address, to_account_address(to, false)); + TRY_RESULT(amount, parse_grams(grams)); + tonlib_api::object_ptr data; - void init_simple_wallet(td::Slice key) { - if (key.empty()) { - dump_keys(); - td::TerminalIO::out() << "Choose public key (hex prefix or #N)"; - cont_ = [this](td::Slice key) { this->init_simple_wallet(key); }; - return; - } - auto r_key_i = to_key_i(key); - if (r_key_i.is_error()) { - td::TerminalIO::out() << "Unknown key id: [" << key << "]\n"; - return; - } - auto key_i = r_key_i.move_as_ok(); + if (use_encryption) { + data = tonlib_api::make_object(message.str()); + } else { + data = tonlib_api::make_object(message.str()); + } + messages.push_back( + tonlib_api::make_object(std::move(address.address), amount.nano, std::move(data))); + return td::Status::OK(); + }; - td::TerminalIO::out() << "Key #" << key_i << "\n" - << "public key: " << td::buffer_to_hex(keys_[key_i].public_key) << "\n"; - - td::TerminalIO::out() << "Enter password (could be empty)"; - cont_ = [this, key = key.str(), key_i](td::Slice password) { this->init_simple_wallet(key, key_i, password); }; - } - - void init_simple_wallet(std::string key, size_t key_i, td::Slice password) { - using tonlib_api::make_object; - if (options_.wallet_version == 1) { - send_query(make_object(make_object( - make_object(keys_[key_i].public_key, keys_[key_i].secret.copy()), - td::SecureString(password))), - [key = std::move(key)](auto r_res) { - if (r_res.is_error()) { - td::TerminalIO::out() << "Can't init wallet with key: [" << key << "] " << r_res.error() << "\n"; - return; - } - td::TerminalIO::out() << to_string(r_res.ok()); - }); + if (from_file) { + TRY_RESULT_PROMISE(cmd_promise, data, td::read_file(parser.read_word().str())); + auto lines = td::full_split(data.as_slice(), '\n'); + for (auto& line : lines) { + td::ConstParser parser(line); + parser.skip_whitespaces(); + if (parser.empty()) { + continue; + } + if (parser.read_word() != "SEND") { + TRY_STATUS_PROMISE(cmd_promise, td::Status::Error("Expected `SEND` in file")); + } + TRY_STATUS_PROMISE(cmd_promise, add_message(parser)); + } } else { - send_query(make_object(make_object( - make_object(keys_[key_i].public_key, keys_[key_i].secret.copy()), - td::SecureString(password))), - [key = std::move(key)](auto r_res) { - if (r_res.is_error()) { - td::TerminalIO::out() << "Can't init wallet with key: [" << key << "] " << r_res.error() << "\n"; - return; - } - td::TerminalIO::out() << to_string(r_res.ok()); - }); + while (parser.skip_whitespaces(), !parser.empty()) { + TRY_STATUS_PROMISE(cmd_promise, add_message(parser)); + } + } + + td::Slice password; // empty by default + using tonlib_api::make_object; + tonlib_api::object_ptr key = + !from_address.secret.empty() + ? make_object( + make_object(from_address.public_key, from_address.secret.copy()), + td::SecureString(password)) + : nullptr; + if (use_fake_key) { + key = make_object(); + } + + bool allow_send_to_uninited = force; + + send_query(make_object( + std::move(key), std::move(from_address.address), 60, + make_object(std::move(messages), allow_send_to_uninited)), + cmd_promise.send_closure(actor_id(this), &TonlibCli::transfer2, estimate_fees)); + } + + void transfer2(bool estimate_fees, td::Result> r_info, + td::Promise cmd_promise) { + if (estimate_fees) { + send_query(tonlib_api::make_object(r_info.ok()->id_, true), + cmd_promise.wrap([](auto&& info) { + td::TerminalIO::out() << "Extimated fees: " << to_string(info); + return td::Unit(); + })); + } else { + send_query(tonlib_api::make_object(r_info.ok()->id_), cmd_promise.wrap([](auto&& info) { + td::TerminalIO::out() << "Transfer sent: " << to_string(info); + return td::Unit(); + })); } } @@ -1280,8 +1605,22 @@ int main(int argc, char* argv[]) { options.use_callbacks_for_network = true; return td::Status::OK(); }); - p.add_option('W', "wallet-version", "do not use this", [&](td::Slice arg) { - options.wallet_version = td::to_integer(arg); + p.add_option('w', "wallet-id", "do not use this", [&](td::Slice arg) { + TRY_RESULT(wallet_id, td::to_integer_safe((arg))); + options.wallet_id = wallet_id; + return td::Status::OK(); + }); + p.add_option('W', "wallet-version", "do not use this (version[.revision])", [&](td::Slice arg) { + td::ConstParser parser(arg); + TRY_RESULT(version, td::to_integer_safe((parser.read_till_nofail('.')))); + options.wallet_version = version; + LOG(INFO) << "Use wallet version = " << version; + if (parser.peek_char() == '.') { + parser.skip('.'); + TRY_RESULT(revision, td::to_integer_safe((parser.read_all()))); + options.wallet_revision = revision; + LOG(INFO) << "Use wallet revision = " << revision; + } return td::Status::OK(); });