From c574ea531724c3b7374708343b6bdf2f472aa0c5 Mon Sep 17 00:00:00 2001 From: IgorKoval Date: Thu, 31 Oct 2024 22:01:42 +0300 Subject: [PATCH] 0.77.0 --- API.md | 241 ++- Cargo.lock | 254 ++-- Changelog.md | 23 + README.md | 2 +- compiler/CMakeLists.txt | 2 +- compiler/liblangutil/Token.h | 4 +- compiler/libsolidity/analysis/TypeChecker.cpp | 95 +- compiler/libsolidity/analysis/TypeChecker.h | 8 +- .../libsolidity/analysis/ViewPureChecker.cpp | 3 +- compiler/libsolidity/ast/AST.cpp | 3 + compiler/libsolidity/ast/AST.h | 2 + compiler/libsolidity/ast/ASTEnums.h | 2 +- compiler/libsolidity/ast/TypeProvider.cpp | 7 +- compiler/libsolidity/ast/TypeProvider.h | 4 +- compiler/libsolidity/ast/Types.cpp | 162 +- compiler/libsolidity/ast/Types.h | 54 +- .../libsolidity/codegen/DictOperations.cpp | 4 +- compiler/libsolidity/codegen/TVMABI.cpp | 142 +- compiler/libsolidity/codegen/TVMABI.hpp | 11 +- compiler/libsolidity/codegen/TVMAnalyzer.cpp | 2 +- compiler/libsolidity/codegen/TVMCommons.cpp | 37 +- compiler/libsolidity/codegen/TVMCommons.hpp | 6 +- .../codegen/TVMContractCompiler.cpp | 42 +- .../codegen/TVMExpressionCompiler.cpp | 16 +- .../codegen/TVMExpressionCompiler.hpp | 2 +- .../libsolidity/codegen/TVMFunctionCall.cpp | 32 +- .../codegen/TVMFunctionCompiler.cpp | 63 +- .../codegen/TVMFunctionCompiler.hpp | 1 + compiler/libsolidity/codegen/TVMPusher.cpp | 73 +- compiler/libsolidity/codegen/TVMPusher.hpp | 40 +- .../libsolidity/codegen/TVMTypeChecker.cpp | 19 +- compiler/libsolidity/codegen/TvmAst.hpp | 14 +- .../libsolidity/codegen/TvmAstVisitor.cpp | 48 +- .../libsolidity/codegen/TvmAstVisitor.hpp | 1 + compiler/libsolidity/parsing/Parser.cpp | 3 + compiler/libsolidity/parsing/Parser.h | 1 + compiler/scripts/install_deps.sh | 41 - compiler/solc/CommandLineInterface.cpp | 20 +- compiler/solc/main.cpp | 9 + lib/stdlib.sol | 54 +- lib/stdlib_sol.tvm | 1347 +++++++++-------- sold/Cargo.toml | 8 +- sold/build.rs | 32 +- sold/src/lib.rs | 108 +- sold/src/main.rs | 2 +- sold/src/printer.rs | 32 +- sold/tests/tests.rs | 25 +- 47 files changed, 1924 insertions(+), 1177 deletions(-) diff --git a/API.md b/API.md index 21b2275d..c87e8263 100644 --- a/API.md +++ b/API.md @@ -162,6 +162,17 @@ When deploying contracts, you should use the latest released version of Solidity * [\.isNone()](#addressisnone) * [\.unpack()](#addressunpack) * [\.transfer()](#addresstransfer) + * [address_std](#address_std) + * [address_std.makeAddrStd()](#address_stdmakeaddrstd) + * [address_std.addrNone](#address_stdaddrnone) + * [\.wid](#address_stdwid) + * [\.value](#address_stdvalue) + * [\.getType()](#address_stdgettype) + * [\.isStdZero()](#address_stdisstdzero) + * [\.isStdAddrWithoutAnyCast()](#address_stdisstdaddrwithoutanycast) + * [\.isNone()](#address_stdisnone) + * [\.unpack()](#address_stdunpack) + * [\.transfer()](#address_stdtransfer) * [mapping](#mapping) * [Keyword `emptyMap`](#keyword-emptymap) * [\.operator[]](#mappingoperator) @@ -204,6 +215,7 @@ When deploying contracts, you should use the latest released version of Solidity * [Keyword `nostorage`](#keyword-nostorage) * [Keyword `public`](#keyword-public) * [Special contract functions](#special-contract-functions) + * [getter](#getter) * [receive](#receive) * [fallback](#fallback) * [onBounce](#onbounce) @@ -1802,7 +1814,7 @@ Returns "non-quiet" integer. If `` is `NaN`, then throws an exception. `T` is function f(quint32 a, quint32 b) private pure { quint32 s = a + b; if (!s.isNaN()) { - uint32 ss = s.get(); + uint32 sum = s.get(); // ... } } @@ -1819,7 +1831,7 @@ Returns "non-quiet" integer. If `` is `NaN`, then returns `default`. `T` is ` ```TVMSolidity function f(quint32 a, quint32 b) private pure { quint32 s = a + b; - uint32 ss = s.getOr(42); // ss is equal to `a + b` or 42 + uint32 sum = s.getOr(42); // sum is equal to `a + b` or 42 // ... } ``` @@ -1835,7 +1847,7 @@ Returns "non-quiet" integer. If `` is `NaN`, then returns default value. `T` ```TVMSolidity function f(quint32 a, quint32 b) private pure { quint32 s = a + b; - uint32 ss = s.getOrDefault(); // ss is equal to `a + b` or 0 + uint32 sum = s.getOrDefault(); // sum is equal to `a + b` or 0 // ... } ``` @@ -1851,7 +1863,7 @@ Returns optional integer. If `` is `NaN`, then returns [null](#keyword-null). ```TVMSolidity function f(quint32 a, quint32 b) private pure { quint32 s = a + b; - optional(uint32) ss = s.toOptional(); // ss is equal to `a + b` or null + optional(uint32) sum = s.toOptional(); // sum is equal to `a + b` or null // ... } ``` @@ -2249,7 +2261,7 @@ str = format("{:06}", 123); // str == "000123" str = format("{:06d}", 123); // str == "000123" str = format("{:06X}", 123); // str == "00007B" str = format("{:6x}", 123); // str == " 7b" -uint128 a = 1 ever; +coins a = 1 ever; str = format("{:t}", a); // str == "1.000000000" a = 123; str = format("{:t}", a); // str == "0.000000123" @@ -2298,8 +2310,8 @@ If `string` object has less than **N** bytes, extra bytes are padded with zero b #### address -`address` represents different types of TVM addresses: **addr_none**, **addr_extern**, -**addr_std** and **addr_var**. TVM Solidity compiler expands `address` type with the following +`address` represents different types of TVM addresses: [**addr_none**, **addr_extern**, +**addr_std** and **addr_var**](https://github.com/ton-blockchain/ton/blob/master/crypto/block/block.tlb#L100C1-L100C10). TVM Solidity compiler expands `address` type with the following members and functions: ##### Object creating @@ -2307,7 +2319,7 @@ members and functions: ##### constructor() ```TVMSolidity -uint address_value; +uint address_value = ...; address addrStd = address(address_value); ``` @@ -2316,9 +2328,9 @@ Constructs `address` of type **addr_std** with zero workchain id and given addre ##### address.makeAddrStd() ```TVMSolidity -int8 wid; -uint address; -address addrStd = address.makeAddrStd(wid, address); +int8 wid = ...; +uint value = ...; +address addrStd = address.makeAddrStd(wid, value); ``` Constructs `address` of type **addr_std** with given workchain id **wid** and value **address_value**. @@ -2380,13 +2392,14 @@ Returns currencies on the balance of the current contract account. ##### \.getType() ```TVMSolidity -
.getType() returns (uint8); +
.getType() returns (uint4); ``` Returns type of the `address`: -0 - **addr_none** -1 - **addr_extern** -2 - **addr_std** + * 0 - `addr_none` + * 1 - `addr_extern` + * 2 - `addr_std` + * 3 - `addr_var` ##### \.isStdZero() @@ -2488,7 +2501,7 @@ In order to clarify flags usage see [this sample](https://github.com/everx-labs/ ```TVMSolidity address dest = ...; -uint128 value = ...; +coins value = ...; bool bounce = ...; uint16 flag = ...; TvmCell body = ...; @@ -2510,6 +2523,102 @@ See example of `address.transfer()` usage: * [giver](https://github.com/everx-labs/samples/blob/master/solidity/7_Giver.sol) +#### address_std + +`address_std` type is same as [address](#address) but can be [addr_std or addr_none](https://github.com/ton-blockchain/ton/blob/master/crypto/block/block.tlb#L100C1-L100C10). + +```TVMSolidity +uint address_value = ...; +address_std addrStd = address_std(address_value); +``` + +Constructs `address_std` of type **addr_std** with zero workchain id and given value. + +##### address_std.makeAddrStd() + +```TVMSolidity +int8 wid; +uint value; +address_std addrStd = address.makeAddrStd(wid, value); +``` + +Constructs `address_std` of type **addr_std** with given workchain id **wid** and value **address_value**. + +##### address_std.addrNone + +```TVMSolidity +address_std addrNone = address_std.addrNone; +``` + +Constructs `address_std` of type **addr_none**. + +##### \.wid + +```TVMSolidity +.wid returns (int8); +``` + +Returns the workchain id of **addr_std**. Throws "range check error" [exception](#tvm-exception-codes) for other `address_std` types. + +##### \.value + +```TVMSolidity +.value returns (uint); +``` + +Returns the `address_std` value of **addr_std**. Throws "range check error" [exception](#tvm-exception-codes) for other `address_std` types. + + +##### \.getType() + +```TVMSolidity +.getType() returns (uint4); +``` + +Returns type of the `address_std`: +* 0 - `addr_none` +* 2 - `addr_std` + +##### \.isStdZero() + +```TVMSolidity +.isStdZero() returns (bool); +``` + +Returns the result of comparison between this `address` with zero `address` of type **addr_std**. + +##### \.isStdAddrWithoutAnyCast() + +```TVMSolidity +.isStdAddrWithoutAnyCast() returns (bool); +``` + +Checks whether this `address_std` is of type **addr_std** without any cast. + +##### \.isNone() + +```TVMSolidity +.isNone() returns (bool); +``` + +Checks whether this `address_std` is of type **addr_none**. + +##### \.unpack() + +```TVMSolidity +.unpack() returns (int8 /*wid*/, uint256 /*value*/); +``` + +Same as [\.unpack()](#addressunpack) + +##### \.transfer() + +```TVMSolidity +.transfer(varuint16 value, bool bounce, uint16 flag, TvmCell body, mapping(uint32 => varuint32) currencies, TvmCell stateInit); +``` + +Same as [\.transfer()](#addresstransfer) + #### mapping TVM Solidity compiler expands `mapping` type with the following functions. In examples @@ -3187,6 +3296,31 @@ contract C { ### Special contract functions +#### getter + +Smart-contract `getter` function is a function that can be called only off-chain. Keyword `getter` is used to mark such functions. `getter` function can not be called on-chain (either external/internal message or onTickTock transaction). They specifically designed to read some data from smart-contracts off-chain. Example: + +```TVMSolidity +contract C { + + address_std m_address; + mapping(uint64 => uint8) m_values; + + function get_address() getter returns (address_std) { + return m_address; + } + + function get_value(uint key) getter returns (uint8) { + return m_values.contains(key) ? m_values.at(key) : 255; + } +} +``` + +Use `ever-cli run` to call getter function. Example: +```bash +ever-cli -j run --abi test_getter_2.abi.json get_value '{"key": 10}'` +``` + #### receive `receive` function is called in two cases: @@ -5129,7 +5263,14 @@ contract ContractCreator { ##### abi.decodeData() ```TVMSolidity -abi.decodeData(ContractName, TvmSlice) returns (uint256 /*pubkey*/, uint64 /*timestamp*/, bool /*constructorFlag*/, Type1 /*var1*/, Type2 /*var2*/, ...); +abi.decodeData(ContractName, TvmSlice) returns ( + uint256 /*pubkey*/, + uint64 /*timestamp*/, + bool /*constructorFlag*/, + Type1 /*var1*/, + Type2 /*var2*/, + ... +); ``` Loads state variables from `TvmSlice` that is obtained from the field `data` of `stateInit`. @@ -5138,31 +5279,31 @@ Example: ``` contract A { - uint a = 111; - uint b = 22; - uint c = 3; - uint d = 44; - address e = address(12); - address f; + uint a = 111; + uint b = 22; + uint c = 3; + uint d = 44; + address e = address(12); + address f; + constructor() {} } contract B { - function f(TvmCell data) public pure { - TvmSlice s = data.toSlice(); - (uint256 pubkey, uint64 timestamp, bool flag, - uint a, uint b, uint c, uint d, address e, address f) = abi.decodeData(A, s); - - // pubkey - pubkey of the contract A - // timestamp - timestamp that used for replay protection - // flag - always is equal to true - // a == 111 - // b == 22 - // c == 3 - // d == 44 - // e == address(12) - // f == address.addrNone - // s.empty() - } + function f(TvmCell data) public pure { + TvmSlice s = data.toSlice(); + (uint256 pubkey, uint64 timestamp, bool flag, + uint a, uint b, uint c, uint d, address e, address f) = abi.decodeData(A, s); + + // pubkey - pubkey of the contract A + // timestamp - timestamp that used for replay protection + // flag - constructor flag is set if the contract is deployed + // a == 111 + // b == 22 + // c == 3 + // d == 44 + // e == address(12) + // f == address.addrNone + } } ``` @@ -5262,7 +5403,7 @@ function mechanics. ```TVMSolidity abi.encodeBody(function, arg0, arg1, arg2, ...) returns (TvmCell); abi.encodeBody(function, callbackFunction, arg0, arg1, arg2, ...) returns (TvmCell); -abi.encodeBody(contract, arg0, arg1, arg2, ...) returns (TvmCell); +abi.encodeBody(ContractName, arg0, arg1, arg2, ...) returns (TvmCell); ``` Constructs a message body for the function call. Body can be used as a payload for [\.transfer()](#addresstransfer). @@ -5376,20 +5517,32 @@ See example of how to use this function: ##### abi.encodeIntMsg() ```TVMSolidity +// (1) abi.encodeIntMsg({ dest: address, - value: uint128, + value: coins, call: {function, [callbackFunction,] arg0, arg1, arg2, ...}, bounce: bool, currencies: mapping(uint32 => varuint32), stateInit: TvmCell }) returns (TvmCell); + +// (2) +abi.encodeIntMsg({ + dest: address, + value: coins, + call: {ContractName, arg0, arg1, arg2, ...}, + bounce: bool, + currencies: mapping(uint32 => varuint32), + stateInit: TvmCell +}) +returns (TvmCell); ``` -Generates an internal outbound message that contains a function call. The result `TvmCell` can be used to send a -message using [tvm.sendrawmsg()](#tvmsendrawmsg). If the `function` is `responsible`, then -`callbackFunction` parameter must be set. +Generates an internal outbound message that contains a function (1) or constructor (2) call. +The result `TvmCell` can be used to send a message using [tvm.sendrawmsg()](#tvmsendrawmsg). +If the `function` is `responsible`, then `callbackFunction` parameter must be set. `dest`, `value` and `call` parameters are mandatory. Another parameters can be omitted. See [\.transfer()](#addresstransfer) where these options and their default values are diff --git a/Cargo.lock b/Cargo.lock index 3bb67f4a..540c9834 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -60,9 +60,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.14" +version = "0.6.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +checksum = "23a1e53f0f5d86382dafe1cf314783b2044280f406e7e1506368220ad11b1338" dependencies = [ "anstyle", "anstyle-parse", @@ -75,33 +75,33 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" +checksum = "8365de52b16c035ff4fcafe0092ba9390540e3e352870ac09933bebcaa2c8c56" [[package]] name = "anstyle-parse" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ "windows-sys", ] [[package]] name = "anstyle-wincon" -version = "3.0.3" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" dependencies = [ "anstyle", "windows-sys", @@ -109,19 +109,20 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.86" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +checksum = "c042108f3ed77fd83760a5fd79b53be043192bb3b9dba91d8c574c0ada7850c8" [[package]] name = "assert_cmd" -version = "2.0.14" +version = "2.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed72493ac66d5804837f480ab3766c72bdfab91a65e565fc54fa9e42db0073a8" +checksum = "dc1835b7f27878de8525dc71410b5a31cdcc5f230aed5ba5df968e09c201b23d" dependencies = [ "anstyle", "bstr", "doc-comment", + "libc", "predicates", "predicates-core", "predicates-tree", @@ -141,9 +142,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "base64" @@ -168,9 +169,9 @@ dependencies = [ [[package]] name = "blst" -version = "0.3.12" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62dc83a094a71d43eeadd254b1ec2d24cb6a0bb6cadce00df51f0db594711a32" +checksum = "4378725facc195f1a538864863f6de233b500a8862747e7f165078a419d5e874" dependencies = [ "cc", "glob", @@ -180,9 +181,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.9.1" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706" +checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" dependencies = [ "memchr", "regex-automata", @@ -203,9 +204,12 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cc" -version = "1.1.5" +version = "1.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "324c74f2155653c90b04f25b2a47a8a631360cb908f92a772695f430c7e31052" +checksum = "c2e7962b54006dcfcc61cb72735f4d89bb97061dd6a7ed882ec6b8ee53714c6f" +dependencies = [ + "shlex", +] [[package]] name = "cfg-if" @@ -238,9 +242,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.9" +version = "4.5.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64acc1846d54c1fe936a78dc189c34e28d3f5afc348403f28ecf53660b9b8462" +checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" dependencies = [ "clap_builder", "clap_derive", @@ -248,9 +252,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.9" +version = "4.5.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb8393d67ba2e7bfaf28a23458e4e2b543cc73a99595511eb207fdb8aede942" +checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" dependencies = [ "anstream", "anstyle", @@ -260,9 +264,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.8" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bac35c6dafb060fd4d275d9a4ffae97917c13a6327903a8be2153cd964f7085" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" dependencies = [ "heck", "proc-macro2", @@ -272,24 +276,24 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] name = "cmake" -version = "0.1.50" +version = "0.1.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" +checksum = "fb1e43aa7fd152b1f968787f7dbcdeb306d1867ff373c69955211876c053f91a" dependencies = [ "cc", ] [[package]] name = "colorchoice" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "const-oid" @@ -299,15 +303,15 @@ checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" dependencies = [ "libc", ] @@ -407,9 +411,9 @@ checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" [[package]] name = "dunce" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" [[package]] name = "ed25519" @@ -438,8 +442,8 @@ dependencies = [ [[package]] name = "ever_abi" -version = "2.6.1" -source = "git+https://github.com/everx-labs/ever-abi.git?tag=2.6.1#9b789948eb3d9be16b080c7c29453cce0be25f15" +version = "2.7.2" +source = "git+https://github.com/everx-labs/ever-abi.git?tag=2.7.2#70f946130a68db322fa7fe735c77e5998c4fefb4" dependencies = [ "anyhow", "byteorder", @@ -456,8 +460,8 @@ dependencies = [ [[package]] name = "ever_assembler" -version = "1.6.3" -source = "git+https://github.com/everx-labs/ever-assembler.git?tag=1.6.3#a663b51ca018fec1af8c499cf5ffd5f0670e10dd" +version = "1.6.14" +source = "git+https://github.com/everx-labs/ever-assembler.git?tag=1.6.14#0569ad4c246813f3b3f2db27b427c67afd23e8e9" dependencies = [ "anyhow", "clap", @@ -474,8 +478,8 @@ dependencies = [ [[package]] name = "ever_block" -version = "1.11.0" -source = "git+https://github.com/everx-labs/ever-block.git?tag=1.11.0#c4d06d5e033897134aac6b54ee077b87775a35b4" +version = "1.11.11" +source = "git+https://github.com/everx-labs/ever-block.git?tag=1.11.11#5d617e2f0a8f7ec2b3e0aab9167280260a5ad7f2" dependencies = [ "aes-ctr", "anyhow", @@ -504,8 +508,8 @@ dependencies = [ [[package]] name = "ever_vm" -version = "2.2.1" -source = "git+https://github.com/everx-labs/ever-vm.git?tag=2.2.1#280daf4d22a04e108881951e32926ed925be86e5" +version = "2.2.12" +source = "git+https://github.com/everx-labs/ever-vm.git?tag=2.2.12#ebd07bab74de939cfc71b1f56aa314cb58695318" dependencies = [ "anyhow", "ever_block", @@ -596,9 +600,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "iana-time-zone" -version = "0.1.60" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -619,9 +623,9 @@ dependencies = [ [[package]] name = "is_terminal_polyfill" -version = "1.70.0" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itoa" @@ -631,9 +635,9 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" dependencies = [ "wasm-bindgen", ] @@ -646,14 +650,14 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.155" +version = "0.2.161" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" [[package]] name = "lockfree" -version = "0.5.1" -source = "git+https://github.com/everx-labs/lockfree.git#bfcb66587dc4ffed9e8e9248995ad2fe8dc3669e" +version = "0.5.2" +source = "git+https://github.com/everx-labs/lockfree.git#2a30df72944ed48255a97defcd387dd4962f3dd5" dependencies = [ "owned-alloc", ] @@ -772,9 +776,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "opaque-debug" @@ -800,15 +804,18 @@ dependencies = [ [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] [[package]] name = "predicates" -version = "3.1.0" +version = "3.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b87bfd4605926cdfefc1c3b5f8fe560e3feca9d5552cf68c466d3d8236c7e8" +checksum = "7e9086cc7640c29a356d1a29fd134380bee9d8f79a17410aa76e7ad295f42c97" dependencies = [ "anstyle", "difflib", @@ -820,15 +827,15 @@ dependencies = [ [[package]] name = "predicates-core" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174" +checksum = "ae8177bee8e75d6846599c6b9ff679ed51e882816914eec639944d7c9aa11931" [[package]] name = "predicates-tree" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf" +checksum = "41b740d195ed3166cd147c8047ec98db0e22ec019eb8eeb76d343b795304fb13" dependencies = [ "predicates-core", "termtree", @@ -836,18 +843,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -884,9 +891,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.5" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", @@ -896,9 +903,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" dependencies = [ "aho-corasick", "memchr", @@ -907,15 +914,15 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver", ] @@ -934,18 +941,18 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.204" +version = "1.0.214" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.204" +version = "1.0.214" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766" dependencies = [ "proc-macro2", "quote", @@ -954,11 +961,12 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.120" +version = "1.0.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" +checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] @@ -974,6 +982,12 @@ dependencies = [ "digest", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signature" version = "2.2.0" @@ -991,7 +1005,7 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "sold" -version = "0.76.0" +version = "0.77.0" dependencies = [ "anyhow", "assert_cmd", @@ -1042,9 +1056,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.71" +version = "2.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b146dcf730474b4bcd16c311627b31ede9ab149045db4d6088b3becaea046462" +checksum = "5023162dfcd14ef8f32034d8bcd4cc5ddc61ef7a247c024a33e24e1f24d21b56" dependencies = [ "proc-macro2", "quote", @@ -1059,18 +1073,18 @@ checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" [[package]] name = "thiserror" -version = "1.0.63" +version = "1.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +checksum = "5d11abd9594d9b38965ef50805c5e469ca9cc6f197f883f717e0269a3057b3d5" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.63" +version = "1.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602" dependencies = [ "proc-macro2", "quote", @@ -1094,9 +1108,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "utf8parse" @@ -1106,9 +1120,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "vte" @@ -1147,19 +1161,20 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" dependencies = [ "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" dependencies = [ "bumpalo", "log", @@ -1172,9 +1187,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1182,9 +1197,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", @@ -1195,9 +1210,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" [[package]] name = "winapi" @@ -1232,9 +1247,9 @@ dependencies = [ [[package]] name = "windows-sys" -version = "0.52.0" +version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ "windows-targets", ] @@ -1315,6 +1330,27 @@ dependencies = [ "zeroize", ] +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "zeroize" version = "1.8.1" diff --git a/Changelog.md b/Changelog.md index 7467d724..b4474658 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,26 @@ +### 0.77.0 (2024-10-31) + +Bugfixes: + * Fixed wrong type conversion. For example: conversion from `stack(varuint)` to `stack(varint)` was supported. But now +it's an error. + * Type checker: `abi.decodeData()` function could take any type for 2d parameter. + * [format()](API.md#format) threw an exception for non `addr_std` address. See [issues #168](https://github.com/everx-labs/TVM-Solidity-Compiler/issues/168). +Now [format()](API.md#format) can take address of any type. + * Fixed bug when you iterate over array of mapping. See [issues #169](https://github.com/everx-labs/TVM-Solidity-Compiler/issues/169). + * Fixed bug when overloading inline function. See [issues #167](https://github.com/everx-labs/TVM-Solidity-Compiler/issues/167). + * Fixed compilation failure on formatted output pattern. See [issues #166](https://github.com/everx-labs/TVM-Solidity-Compiler/issues/166). + +Compiler features: + * Supported [ABI 2.7](https://github.com/everx-labs/ever-abi/blob/master/CHANGELOG.md#version-270) + * Supported [getters](API.md#getter). + * Supported [address_std](API.md#address_std) type. + * Supported encoding internal message to call constructor. See option 2 [abi.encodeIntMsg()](API.md#abiencodeintmsg). + +Optimizations: + * optimized decoding function parameters if the function marked as `externalMsg` or `internalMsg`. + +Function [\.getType()](API.md#addressgettype) now returns `uint4` instead of `uint8`. + ### 0.76.0 (2024-07-18) Compiler features: diff --git a/README.md b/README.md index a4098ce8..967e8a85 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ cmake --build . --config Release -- /m * [Code samples](https://github.com/everx-labs/samples/tree/master/solidity) in TVM Solidity * [ever-cli](https://github.com/everx-labs/ever-cli) command line interface for TVM compatible blockchains * Example of usage `ever-cli` for working (deploying, calling etc.) with TVM compatible blockchains can be found there: [Write smart contract in Solidity](https://docs.ton.dev/86757ecb2/p/950f8a-write-smart-contract-in-solidity) - * [Changelog](https://github.com/everx-labs/TVM-Solidity-Compiler/blob/master/Changelog_TON.md) + * [Changelog](./Changelog.md) ## License [GNU GENERAL PUBLIC LICENSE Version 3](./LICENSE) diff --git a/compiler/CMakeLists.txt b/compiler/CMakeLists.txt index 20815f8a..e841a083 100644 --- a/compiler/CMakeLists.txt +++ b/compiler/CMakeLists.txt @@ -21,7 +21,7 @@ include(EthPolicy) eth_policy() # project name and version should be set after cmake_policy CMP0048 -set(PROJECT_VERSION "0.76.0") +set(PROJECT_VERSION "0.77.0") # OSX target needed in order to support std::visit set(CMAKE_OSX_DEPLOYMENT_TARGET "10.14") project(solidity VERSION ${PROJECT_VERSION} LANGUAGES C CXX) diff --git a/compiler/liblangutil/Token.h b/compiler/liblangutil/Token.h index 35f415ee..cc6b11af 100644 --- a/compiler/liblangutil/Token.h +++ b/compiler/liblangutil/Token.h @@ -182,6 +182,7 @@ namespace solidity::langutil K(Override, "override", 0) \ K(Payable, "payable", 0) \ K(Public, "public", 0) \ + K(Getter, "getter", 0) \ K(Pragma, "pragma", 0) \ K(Private, "private", 0) \ K(Pure, "pure", 0) \ @@ -244,6 +245,7 @@ namespace solidity::langutil K(Bytes, "bytes", 0) \ K(String, "string", 0) \ K(Address, "address", 0) \ + K(AddressStd, "address_std", 0) \ K(Bool, "bool", 0) \ K(TvmCell, "TvmCell", 0) \ K(TvmSlice, "TvmSlice", 0) \ @@ -368,7 +370,7 @@ namespace TokenTraits constexpr bool isVariableVisibilitySpecifier(Token op) { return op == Token::Public || op == Token::Private || op == Token::Internal; } - constexpr bool isVisibilitySpecifier(Token op) { return isVariableVisibilitySpecifier(op) || op == Token::External; } + constexpr bool isVisibilitySpecifier(Token op) { return isVariableVisibilitySpecifier(op) || op == Token::External || op == Token::Getter; } constexpr bool isStateMutabilitySpecifier(Token op) { diff --git a/compiler/libsolidity/analysis/TypeChecker.cpp b/compiler/libsolidity/analysis/TypeChecker.cpp index 2b43f488..1b39e43f 100644 --- a/compiler/libsolidity/analysis/TypeChecker.cpp +++ b/compiler/libsolidity/analysis/TypeChecker.cpp @@ -427,6 +427,7 @@ TypePointers TypeChecker::checkSliceDecode(std::vector(curType); auto intKey = to(mappingType->keyType()); - auto addrKey = to(mappingType->keyType()); - if (intKey == nullptr && addrKey == nullptr) { + auto addrKey = isIn(mappingType->keyType()->category(), Type::Category::Address, Type::Category::AddressStd); + if (intKey == nullptr && !addrKey) { printError( "Key type of the mapping must be " "any of int/uint types with M from 8 to 256 or std address."); @@ -691,6 +693,7 @@ bool TypeChecker::isBadAbiType( } case Type::Category::Address: + case Type::Category::AddressStd: case Type::Category::Bool: case Type::Category::Contract: case Type::Category::Enum: @@ -980,6 +983,7 @@ bool TypeChecker::visit(VariableDeclaration const& _variable) auto mapType = dynamic_cast(varType); switch (mapType->keyType()->category()) { case Type::Category::Address: + case Type::Category::AddressStd: case Type::Category::Array: // usual arrays (e.g. uint[]) are checked in another place case Type::Category::Bool: case Type::Category::Contract: @@ -2315,6 +2319,7 @@ TypeChecker::Result TypeChecker::canStoreToBuilder(Type const* type, bool _topTy case Type::Category::TvmSlice: return {_topType, std::nullopt}; case Type::Category::Address: + case Type::Category::AddressStd: case Type::Category::Array: case Type::Category::Bool: case Type::Category::Contract: @@ -2383,6 +2388,7 @@ void TypeChecker::checkStoreQ(Expression const& _argument) { } case Type::Category::TvmCell: case Type::Category::Address: + case Type::Category::AddressStd: case Type::Category::Contract: case Type::Category::TvmSlice: case Type::Category::Integer: @@ -2530,17 +2536,14 @@ TypeChecker::getFunctionDefinition(Expression const* expr) { return dynamic_cast(declaration); } -std::pair +std::pair TypeChecker::getConstructorDefinition(Expression const* expr) { - auto contractType = getContractType(expr); - if (contractType == nullptr) { - return {}; - } - FunctionDefinition const* constr = contractType->contractDefinition().constructor(); - if (constr == nullptr) { - return {true, nullptr}; + ContractType const* contractType = getContractType(expr); + FunctionDefinition const* constr{}; + if (contractType != nullptr) { + constr = contractType->contractDefinition().constructor(); } - return {true, constr}; + return {contractType, constr}; } ContractType const* TypeChecker::getContractType(Expression const* expr) { @@ -2789,20 +2792,21 @@ void TypeChecker::typeCheckFunctionGeneralChecks( std::vector> const& argumentNames = _functionCall.names(); bool isFunctionWithDefaultValues = false; { - auto ma = dynamic_cast(&_functionCall.expression()); - if (ma && ma->memberName() == "transfer" && dynamic_cast(ma->expression().annotation().type)) { - isFunctionWithDefaultValues = true; - } - if (ma && dynamic_cast(ma->expression().annotation().type)) { - if (ma->memberName() == "encodeStateInit" || - ma->memberName() == "buildStateInit" || - ma->memberName() == "buildDataInit" || - ma->memberName() == "encodeData" || - ma->memberName() == "encodeOldDataInit" || - ma->memberName() == "buildExtMsg" || - ma->memberName() == "encodeIntMsg" || - ma->memberName() == "buildIntMsg") - isFunctionWithDefaultValues = true; + if (auto ma = dynamic_cast(&_functionCall.expression())) { + auto category = ma->expression().annotation().type->category(); + if (ma->memberName() == "transfer" && (category == Type::Category::Address || category == Type::Category::AddressStd)) + isFunctionWithDefaultValues = true; + if (dynamic_cast(ma->expression().annotation().type)) { + if (ma->memberName() == "encodeStateInit" || + ma->memberName() == "buildStateInit" || + ma->memberName() == "buildDataInit" || + ma->memberName() == "encodeData" || + ma->memberName() == "encodeOldDataInit" || + ma->memberName() == "buildExtMsg" || + ma->memberName() == "encodeIntMsg" || + ma->memberName() == "buildIntMsg") + isFunctionWithDefaultValues = true; + } } } @@ -3144,7 +3148,7 @@ void TypeChecker::typeCheckFunctionGeneralChecks( } FunctionDefinition const* -TypeChecker::checkPubFunctionAndGetDefinition(Expression const& arg, bool printError) { +TypeChecker::checkPubFunctionAndGetDefinition(Expression const& arg, bool printError) const { FunctionDefinition const* funcDef = getFunctionDefinition(&arg); if (funcDef) { if (!funcDef->isPublic()) { @@ -3170,28 +3174,36 @@ TypeChecker::checkPubFunctionAndGetDefinition(Expression const& arg, bool printE } FunctionDefinition const* -TypeChecker::checkPubFunctionOrContractTypeAndGetDefinition(Expression const& arg) { - FunctionDefinition const* funcDef = checkPubFunctionAndGetDefinition(arg); +TypeChecker::checkPubFunctionOrContractTypeAndGetDefinition(Expression const& arg) const { + FunctionDefinition const* funcDef = checkPubFunctionAndGetDefinition(arg, false); if (funcDef) { return funcDef; } - const auto &[isContract, constructorDef] = getConstructorDefinition(&arg); - if (!isContract) { + const auto &[contract, constructorDef] = getConstructorDefinition(&arg); + if (contract == nullptr) { m_errorReporter.fatalTypeError( 4974_error, arg.location(), - "Function or contract type required, but " + + "Expected function or contract type, but " + type(arg)->toString(true) + " provided." ); + } else if (constructorDef == nullptr) { + m_errorReporter.typeError( + 2672_error, + arg.location(), + SecondarySourceLocation() + .append("Contract definition is here:", contract->contractDefinition().location()), + "Contract has no constructor." + ); } return constructorDef; } void TypeChecker::checkInitList(InitializerList const* list, ContractType const& ct, - langutil::SourceLocation const& _functionCallLocation -) { + SourceLocation const& _functionCallLocation +) const { std::vector stateVariables; for (auto const &[v, _, ___] : ct.stateVariables()) { boost::ignore_unused(_); @@ -3716,7 +3728,7 @@ bool TypeChecker::visit(FunctionCall const& _functionCall) case FunctionType::Kind::TVMSlicePreloadQ: { checkAtLeastOneArg(); - TypePointers members = checkSliceDecode(_functionCall.arguments()); // TODO make for Q + TypePointers members = checkSliceDecodeQ(_functionCall.arguments()); if (members.size() == 1) returnTypes = TypePointers{TypeProvider::optional(members.at(0))}; else @@ -3736,7 +3748,8 @@ bool TypeChecker::visit(FunctionCall const& _functionCall) std::string("Expected two arguments.") ); } - FunctionDefinition const* functionDeclaration = checkPubFunctionOrContractTypeAndGetDefinition(*arguments.front().get()); + FunctionDefinition const* functionDeclaration = + checkPubFunctionOrContractTypeAndGetDefinition(*arguments.front().get()); if (functionDeclaration != nullptr) { // if nullptr => default constructor if (functionDeclaration->isResponsible()) { returnTypes.push_back(TypeProvider::uint(32)); // callback function @@ -3758,7 +3771,8 @@ bool TypeChecker::visit(FunctionCall const& _functionCall) std::string("Expected one argument.") ); } - FunctionDefinition const* functionDeclaration = checkPubFunctionOrContractTypeAndGetDefinition(*arguments.front().get()); + FunctionDefinition const* functionDeclaration = + checkPubFunctionOrContractTypeAndGetDefinition(*arguments.front().get()); if (functionDeclaration != nullptr) { // if nullptr => default constructor if (functionDeclaration->isResponsible()) { returnTypes.push_back(TypeProvider::uint(32)); // callback function @@ -3811,6 +3825,7 @@ bool TypeChecker::visit(FunctionCall const& _functionCall) _functionCall.location(), std::string("Expected two arguments.") ); + expectType(*arguments.at(1), *TypeProvider::tvmslice(), false); } else if (functionType->kind() == FunctionType::Kind::TVMSliceLoadStateVars) { @@ -4082,7 +4097,7 @@ bool TypeChecker::visit(FunctionCall const& _functionCall) returnTypes = functionType->returnParameterTypes(); break; } - case FunctionType::Kind::ABIBuildIntMsg: { + case FunctionType::Kind::ABIEncodeIntMsg: { checkHasNamedParams(); for (const std::string name : {"dest", "call", "value"}) { @@ -4100,11 +4115,7 @@ bool TypeChecker::visit(FunctionCall const& _functionCall) int index = findName("call"); index != -1 ) { - auto callList = dynamic_cast(arguments.at(index).get()); - if (callList) { - // now, we ignore constructor call, because in this case we must set stateInit - checkPubFunctionAndGetDefinition(*callList->function(), true); - + if (auto callList = dynamic_cast(arguments.at(index).get())) { std::vector params; params.push_back(callList->function()); for (const ASTPointer & p : callList->arguments()) { diff --git a/compiler/libsolidity/analysis/TypeChecker.h b/compiler/libsolidity/analysis/TypeChecker.h index e2500124..cbc12539 100644 --- a/compiler/libsolidity/analysis/TypeChecker.h +++ b/compiler/libsolidity/analysis/TypeChecker.h @@ -146,12 +146,12 @@ class TypeChecker: private ASTConstVisitor void checkStoreQ(Expression const& _argument); void typeCheckTvmEncodeFunctions(FunctionCall const& _functionCall); static FunctionDefinition const* getFunctionDefinition(Expression const* expr); - static std::pair getConstructorDefinition(Expression const* expr); + static std::pair getConstructorDefinition(Expression const* expr); static ContractType const* getContractType(Expression const* expr); - FunctionDefinition const* checkPubFunctionAndGetDefinition(Expression const& arg, bool printError = false); - FunctionDefinition const* checkPubFunctionOrContractTypeAndGetDefinition(Expression const& arg); + FunctionDefinition const* checkPubFunctionAndGetDefinition(Expression const& arg, bool printError = false) const; + FunctionDefinition const* checkPubFunctionOrContractTypeAndGetDefinition(Expression const& arg) const; void checkInitList(InitializerList const* list, ContractType const& ct, - langutil::SourceLocation const& _functionCallLocation); + langutil::SourceLocation const& _functionCallLocation) const; void checkCallList( std::vector const& arguments, FunctionCall const& _functionCall, diff --git a/compiler/libsolidity/analysis/ViewPureChecker.cpp b/compiler/libsolidity/analysis/ViewPureChecker.cpp index 1366a734..27e78892 100644 --- a/compiler/libsolidity/analysis/ViewPureChecker.cpp +++ b/compiler/libsolidity/analysis/ViewPureChecker.cpp @@ -82,7 +82,8 @@ void ViewPureChecker::endVisit(FunctionDefinition const& _funDef) !_funDef.isFallback() && !_funDef.isReceive() && !_funDef.virtualSemantics() && - !_funDef.isInlineAssembly() + !_funDef.isInlineAssembly() && + _funDef.visibility() != Visibility::Getter ) m_errorReporter.warning( 2018_error, diff --git a/compiler/libsolidity/ast/AST.cpp b/compiler/libsolidity/ast/AST.cpp index 9e71380f..9221938a 100644 --- a/compiler/libsolidity/ast/AST.cpp +++ b/compiler/libsolidity/ast/AST.cpp @@ -435,6 +435,7 @@ FunctionTypePointer FunctionDefinition::functionType(bool _internal) const switch (visibility()) { case Visibility::Default: + case Visibility::Getter: solAssert(false, "visibility() should not return Default"); case Visibility::Private: case Visibility::Internal: @@ -455,6 +456,7 @@ FunctionTypePointer FunctionDefinition::functionType(bool _internal) const return {}; case Visibility::Public: case Visibility::External: + case Visibility::Getter: return TypeProvider::function(*this, FunctionType::Kind::External); } } @@ -830,6 +832,7 @@ FunctionTypePointer VariableDeclaration::functionType(bool _internal) const switch (visibility()) { case Visibility::Default: + case Visibility::Getter: solAssert(false, "visibility() should not return Default"); case Visibility::Private: case Visibility::Internal: diff --git a/compiler/libsolidity/ast/AST.h b/compiler/libsolidity/ast/AST.h index 93ddaaa1..09a159ec 100644 --- a/compiler/libsolidity/ast/AST.h +++ b/compiler/libsolidity/ast/AST.h @@ -242,6 +242,8 @@ class Declaration: public ASTNode, public Scopable return "private"; case Visibility::External: return "external"; + case Visibility::Getter: + return "getter"; default: solAssert(false, "Invalid visibility specifier."); } diff --git a/compiler/libsolidity/ast/ASTEnums.h b/compiler/libsolidity/ast/ASTEnums.h index d2e2d33a..b76baf14 100644 --- a/compiler/libsolidity/ast/ASTEnums.h +++ b/compiler/libsolidity/ast/ASTEnums.h @@ -37,7 +37,7 @@ enum class VirtualLookup { Static, Virtual, Super }; enum class StateMutability { Pure, View, NonPayable }; /// Visibility ordered from restricted to unrestricted. -enum class Visibility { Default, Private, Internal, Public, External }; +enum class Visibility { Default, Private, Internal, Public, External, Getter }; enum class Arithmetic { Checked, Wrapping }; diff --git a/compiler/libsolidity/ast/TypeProvider.cpp b/compiler/libsolidity/ast/TypeProvider.cpp index 701d4f7d..0d53c53d 100644 --- a/compiler/libsolidity/ast/TypeProvider.cpp +++ b/compiler/libsolidity/ast/TypeProvider.cpp @@ -46,6 +46,7 @@ std::unique_ptr TypeProvider::m_variant; TupleType const TypeProvider::m_emptyTuple{}; AddressType const TypeProvider::m_address{}; +AddressStdType const TypeProvider::m_addressStd{}; InitializerListType const TypeProvider::m_initializerList{}; CallListType const TypeProvider::m_callList{}; @@ -1184,7 +1185,7 @@ void TypeProvider::reset() instance().m_stringLiteralTypes.clear(); instance().m_ufixedMxN.clear(); instance().m_fixedMxN.clear(); - instance().m_varinterger.clear(); + instance().m_varinteger.clear(); } template @@ -1252,6 +1253,8 @@ Type const* TypeProvider::fromElementaryTypeName(ElementaryTypeNameToken const& return fixedPoint(128, 18, FixedPointType::Modifier::Unsigned); case Token::Address: return address(); + case Token::AddressStd: + return addressStd(); case Token::Bool: return boolean(); case Token::TvmCell: @@ -1404,7 +1407,7 @@ StringLiteralType const* TypeProvider::stringLiteral(std::string const& literal) } VarIntegerType const* TypeProvider::varinteger(unsigned m, IntegerType::Modifier _modifier) { - auto& map = instance().m_varinterger; + auto& map = instance().m_varinteger; auto i = map.find(std::make_pair(m, _modifier)); if (i != map.end()) return i->second.get(); diff --git a/compiler/libsolidity/ast/TypeProvider.h b/compiler/libsolidity/ast/TypeProvider.h index c19bc075..9c04ae05 100644 --- a/compiler/libsolidity/ast/TypeProvider.h +++ b/compiler/libsolidity/ast/TypeProvider.h @@ -89,6 +89,7 @@ class TypeProvider static ArraySliceType const* arraySlice(ArrayType const& _arrayType); static AddressType const* address() noexcept { return &m_address; } + static AddressStdType const* addressStd() noexcept { return &m_addressStd; } static InitializerListType const* initializerList() noexcept { return &m_initializerList; } static CallListType const* callList() noexcept { return &m_callList; } @@ -244,6 +245,7 @@ class TypeProvider static TupleType const m_emptyTuple; static AddressType const m_address; + static AddressStdType const m_addressStd; static InitializerListType const m_initializerList; static CallListType const m_callList; static std::array, 257> const m_intM; @@ -255,7 +257,7 @@ class TypeProvider static std::array, 32> const m_bytesM; static std::array, 9> const m_magics; ///< MagicType's except MetaType - std::map, std::unique_ptr> m_varinterger{}; + std::map, std::unique_ptr> m_varinteger{}; std::map, std::unique_ptr> m_ufixedMxN{}; std::map, std::unique_ptr> m_fixedMxN{}; std::map> m_stringLiteralTypes{}; diff --git a/compiler/libsolidity/ast/Types.cpp b/compiler/libsolidity/ast/Types.cpp index 40452886..99b8ed38 100644 --- a/compiler/libsolidity/ast/Types.cpp +++ b/compiler/libsolidity/ast/Types.cpp @@ -516,7 +516,7 @@ BoolResult AddressType::isImplicitlyConvertibleTo(Type const& _convertTo) const if (Type::isImplicitlyConvertibleTo(_convertTo)) return true; - return _convertTo.category() == category(); + return _convertTo.category() == Category::Address || _convertTo.category() == Category::AddressStd; } BoolResult AddressType::isExplicitlyConvertibleTo(Type const& _convertTo) const @@ -560,11 +560,6 @@ TypeResult AddressType::binaryOperatorResult(Token _operator, Type const* _other return Type::commonType(this, _other); } -bool AddressType::operator==(Type const& _other) const -{ - return _other.category() == category(); -} - MemberList::MemberMap AddressType::nativeMembers(ASTNode const*) const { MemberList::MemberMap members = { @@ -586,7 +581,7 @@ MemberList::MemberMap AddressType::nativeMembers(ASTNode const*) const )); members.emplace_back("getType", TypeProvider::function( TypePointers{}, - TypePointers{TypeProvider::uint(8)}, + TypePointers{TypeProvider::uint(4)}, strings{}, strings{std::string()}, FunctionType::Kind::AddressType, @@ -620,6 +615,107 @@ MemberList::MemberMap AddressType::nativeMembers(ASTNode const*) const return members; } +std::string AddressStdType::richIdentifier() const +{ + return "t_address_std"; +} + +std::string AddressStdType::toString(bool) const { + return "address_std"; +} + +std::string AddressStdType::canonicalName() const { + return "address_std"; +} + +u256 AddressStdType::literalValue(Literal const* _literal) const +{ + solAssert(_literal, ""); + solAssert(_literal->value().substr(0, 2) == "0x", ""); + return u256(_literal->valueWithoutUnderscores()); +} + +BoolResult AddressStdType::isImplicitlyConvertibleTo(Type const& _convertTo) const { + if (Type::isImplicitlyConvertibleTo(_convertTo)) + return true; + + return _convertTo.category() == Category::Address || _convertTo.category() == Category::AddressStd; +} + +BoolResult AddressStdType::isExplicitlyConvertibleTo(Type const& _convertTo) const { + if ((_convertTo.category() == category()) || isImplicitlyConvertibleTo(_convertTo)) + return true; + else if (dynamic_cast(&_convertTo)) + return true; + + return false; +} + +TypeResult AddressStdType::unaryOperatorResult(Token _operator) const +{ + return _operator == Token::Delete ? TypeProvider::emptyTuple() : nullptr; +} + + +TypeResult AddressStdType::binaryOperatorResult(Token _operator, Type const* _other) const +{ + if (!TokenTraits::isCompareOp(_operator)) + return TypeResult::err("Arithmetic operations on addresses are not supported. Convert to integer first before using them."); + + return Type::commonType(this, _other); +} + +MemberList::MemberMap AddressStdType::nativeMembers(ASTNode const*) const { + MemberList::MemberMap members = { + {"wid", TypeProvider::integer(8, IntegerType::Modifier::Signed)}, + {"value", TypeProvider::uint256()}, + {"isStdZero", TypeProvider::function(strings(), strings{"bool"}, FunctionType::Kind::AddressIsZero, StateMutability::Pure)}, + {"isNone", TypeProvider::function(strings(), strings{"bool"}, FunctionType::Kind::AddressIsZero, StateMutability::Pure)}, + }; + members.emplace_back("unpack", TypeProvider::function( + TypePointers{}, + TypePointers{TypeProvider::integer(8, IntegerType::Modifier::Signed), TypeProvider::uint256()}, + strings{}, + strings{std::string(), std::string()}, + FunctionType::Kind::AddressUnpack, + StateMutability::Pure + )); + members.emplace_back("getType", TypeProvider::function( + TypePointers{}, + TypePointers{TypeProvider::uint(4)}, + strings{}, + strings{std::string()}, + FunctionType::Kind::AddressType, + StateMutability::Pure + )); + members.emplace_back("isStdAddrWithoutAnyCast", TypeProvider::function( + TypePointers{}, + TypePointers{TypeProvider::boolean()}, + strings{}, + strings{std::string()}, + FunctionType::Kind::AddressIsStdAddrWithoutAnyCast, + StateMutability::Pure + )); + members.emplace_back("transfer", TypeProvider::function( + { + TypeProvider::coins(), + TypeProvider::boolean(), + TypeProvider::uint(16), + TypeProvider::tvmcell(), + TypeProvider::extraCurrencyCollection(), + TypeProvider::tvmcell(), + }, + {}, + {"value", "bounce", "flag", "body", "currencies", "stateInit"}, + {}, + FunctionType::Kind::AddressTransfer, + StateMutability::Pure, + nullptr, + FunctionType::Options::withArbitraryParameters() + )); + return members; +} + namespace { @@ -722,7 +818,7 @@ BoolResult IntegerType::isExplicitlyConvertibleTo(Type const& _convertTo) const category == Type::Category::FixedPoint ) return true; - else if (dynamic_cast(&_convertTo) || dynamic_cast(&_convertTo)) + else if (dynamic_cast(&_convertTo) || dynamic_cast(&_convertTo) || dynamic_cast(&_convertTo)) return !isSigned(); else if (auto fixedBytesType = dynamic_cast(&_convertTo)) return (!isSigned() && (numBits() == fixedBytesType->numBytes() * 8)); @@ -1198,7 +1294,7 @@ BoolResult RationalNumberType::isExplicitlyConvertibleTo(Type const& _convertTo) auto category = _convertTo.category(); if (category == Category::FixedBytes) return false; - else if (dynamic_cast(&_convertTo) || dynamic_cast(&_convertTo)) + else if (dynamic_cast(&_convertTo) || dynamic_cast(&_convertTo) || dynamic_cast(&_convertTo)) return (m_value == 0) || (!isNegative() && !isFractional() && @@ -1570,7 +1666,7 @@ BoolResult FixedBytesType::isExplicitlyConvertibleTo(Type const& _convertTo) con return true; else if (auto integerType = dynamic_cast(&_convertTo)) return (!integerType->isSigned() && integerType->numBits() == numBytes() * 8); - else if (dynamic_cast(&_convertTo)) + else if (dynamic_cast(&_convertTo) || dynamic_cast(&_convertTo)) return numBytes() == 32; return false; @@ -1716,7 +1812,7 @@ BoolResult ContractType::isExplicitlyConvertibleTo(Type const& _convertTo) const if (m_super) return false; - if (dynamic_cast(&_convertTo)) + if (dynamic_cast(&_convertTo) || dynamic_cast(&_convertTo)) return true; return isImplicitlyConvertibleTo(_convertTo); @@ -3267,7 +3363,7 @@ std::string FunctionType::richIdentifier() const case Kind::LogTVM: id += "logtvm"; break; case Kind::TVMAccept: id += "tvmaccept"; break; - case Kind::ABIBuildIntMsg: id += "abibuildintmsg"; break; + case Kind::ABIEncodeIntMsg: id += "abibuildintmsg"; break; case Kind::ABICodeSalt: id += "abicodesalt"; break; case Kind::ABIDecodeFunctionParams: id += "abidecodefunctionparams"; break; case Kind::ABIDecodeData: id += "abidecodestatevars"; break; @@ -4220,10 +4316,6 @@ std::string NullType::richIdentifier() const { return "null"; } -bool NullType::operator==(Type const& _other) const { - return _other.category() == category(); -} - std::string NullType::toString(bool /*_short*/) const { return "null"; } @@ -4241,10 +4333,6 @@ std::string EmptyMapType::richIdentifier() const { return "emptyMap"; } -bool EmptyMapType::operator==(Type const& _other) const { - return _other.category() == category(); -} - std::string EmptyMapType::toString(bool /*_short*/) const { return "emptyMap"; } @@ -4274,6 +4362,11 @@ std::string NanType::toString(bool) const return "NaN"; } +std::string NanType::canonicalName() const +{ + return "NaN"; +} + std::string TypeType::richIdentifier() const { return "t_type" + identifierList(actualType()); @@ -4395,6 +4488,16 @@ MemberList::MemberMap TypeType::nativeMembers(ASTNode const* _currentScope) cons FunctionType::Kind::AddressMakeAddrStd, StateMutability::Pure )); + } else if (m_actualType->category() == Category::AddressStd) { + members.emplace_back("addrNone", TypeProvider::addressStd()); + members.emplace_back("makeAddrStd", TypeProvider::function( + TypePointers{TypeProvider::integer(8, IntegerType::Modifier::Signed), TypeProvider::uint256()}, + TypePointers{TypeProvider::addressStd()}, + strings{std::string(), std::string()}, + strings{std::string()}, + FunctionType::Kind::AddressMakeAddrStd, + StateMutability::Pure + )); } else if (m_actualType->category() == Category::UserDefinedValueType) { @@ -4745,7 +4848,7 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const "stateInit", // can be omitted }, {{}}, - FunctionType::Kind::ABIBuildIntMsg, + FunctionType::Kind::ABIEncodeIntMsg, StateMutability::Pure, nullptr, FunctionType::Options::withArbitraryParameters() @@ -5117,7 +5220,7 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const "stateInit", // can be omitted }, {{}}, - FunctionType::Kind::ABIBuildIntMsg, + FunctionType::Kind::ABIEncodeIntMsg, StateMutability::Pure, nullptr, FunctionType::Options::withArbitraryParameters() @@ -6625,6 +6728,11 @@ MemberList::MemberMap Variant::nativeMembers(ASTNode const* /*_currentScope*/) c return members; } +bool TvmVectorType::operator==(Type const& _other) const { + auto vect = to(&_other); + return vect && *this->valueType() == *vect->valueType(); +} + TypeResult TvmVectorType::unaryOperatorResult(Token _operator) const { if (_operator == Token::Delete) return TypeProvider::emptyTuple(); @@ -6720,6 +6828,11 @@ TypeResult TvmStackType::unaryOperatorResult(Token _operator) const { return nullptr; } +bool TvmStackType::operator==(Type const& _other) const { + auto stack = to(&_other); + return stack && *this->valueType() == *stack->valueType(); +} + MemberList::MemberMap TvmStackType::nativeMembers(const ASTNode *) const { MemberList::MemberMap members = @@ -7167,6 +7280,11 @@ MemberList::MemberMap StringBuilderType::nativeMembers(const ASTNode *) const { return members; } +bool VarIntegerType::operator==(Type const& _other) const { + auto varInt = to(&_other); + return varInt && m_int == varInt->m_int; +} + BoolResult VarIntegerType::isImplicitlyConvertibleTo(Type const& _convertTo) const { return m_int.isImplicitlyConvertibleTo(_convertTo); } diff --git a/compiler/libsolidity/ast/Types.h b/compiler/libsolidity/ast/Types.h index 420bdece..fc9d0b79 100644 --- a/compiler/libsolidity/ast/Types.h +++ b/compiler/libsolidity/ast/Types.h @@ -194,14 +194,9 @@ class Type Module, InaccessibleDynamic, TvmCell, TvmSlice, TvmBuilder, StringBuilder, TvmVector, TvmStack, Variant, - VarInteger, - QInteger, - QBool, + VarInteger, QInteger, QBool, InitializerList, CallList, // <-- variables of that types can't be declared in solidity contract - Optional, - Null, - EmptyMap, - TVMNaN + Optional, Null, EmptyMap, TVMNaN, AddressStd }; /// @returns a pointer to _a or _b if the other is implicitly convertible to it or nullptr otherwise @@ -446,7 +441,36 @@ class AddressType: public Type TypeResult unaryOperatorResult(Token _operator) const override; TypeResult binaryOperatorResult(Token _operator, Type const* _other) const override; - bool operator==(Type const& _other) const override; + unsigned calldataEncodedSize(bool _padded = true) const override { return _padded ? 32 : 160 / 8; } + unsigned storageBytes() const override { return 160 / 8; } + bool leftAligned() const override { return false; } + bool isValueType() const override { return true; } + bool nameable() const override { return true; } + + MemberList::MemberMap nativeMembers(ASTNode const*) const override; + + std::string toString(bool _withoutDataLocation) const override; + std::string canonicalName() const override; + + u256 literalValue(Literal const* _literal) const override; + + Type const* encodingType() const override { return this; } + TypeResult interfaceType(bool) const override { return this; } +}; + +/** + * Type for std or none addresses. + */ +class AddressStdType: public Type +{ +public: + Category category() const override { return Category::AddressStd; } + + std::string richIdentifier() const override; + BoolResult isImplicitlyConvertibleTo(Type const& _other) const override; + BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override; + TypeResult unaryOperatorResult(Token _operator) const override; + TypeResult binaryOperatorResult(Token _operator, Type const* _other) const override; unsigned calldataEncodedSize(bool _padded = true) const override { return _padded ? 32 : 160 / 8; } unsigned storageBytes() const override { return 160 / 8; } @@ -767,7 +791,7 @@ class TvmVectorType: public Type public: TvmVectorType(Type const* _type): m_type(_type) {} - + bool operator==(Type const& _other) const override; Category category() const override { return Category::TvmVector; } bool isValueType() const override { return true; } std::string richIdentifier() const override; @@ -793,7 +817,7 @@ class TvmStackType: public Type public: TvmStackType(Type const* _type): m_type(_type) {} - + bool operator==(Type const& _other) const override; Category category() const override { return Category::TvmStack; } bool isValueType() const override { return true; } std::string richIdentifier() const override; @@ -873,6 +897,7 @@ class VarIntegerType: public Type { public: explicit VarIntegerType(uint32_t _n, IntegerType::Modifier _modifier) : m_n{_n}, m_int{(_n - 1) * 8, _modifier} {} + bool operator==(Type const& _other) const override; BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override; BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override; Category category() const override { return Category::VarInteger; } @@ -898,7 +923,6 @@ class QIntegerType: public Type explicit QIntegerType(uint32_t _n, IntegerType::Modifier _modifier) : m_int{std::make_unique(_n, _modifier)} {} BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override; -// BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override; Category category() const override { return Category::QInteger; } bool isValueType() const override { return true; } bool operator==(Type const& _other) const override; @@ -920,7 +944,6 @@ class QBoolType: public Type public: explicit QBoolType() = default; BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override; -// BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override; Category category() const override { return Category::QBool; } bool isValueType() const override { return true; } std::string richIdentifier() const override { return "t_qbool"; } @@ -1545,12 +1568,12 @@ class FunctionType: public Type BlsG1MultiExp, BlsG2MultiExp, - ABIBuildIntMsg, ///< abi.encodeIntMsg() ABICodeSalt, ///< abi.codeSalt() ABIDecodeData, ///< abi.decodeData(contract_name, slice) ABIDecodeFunctionParams, ///< abi.decodeFunctionParams() ABIEncodeBody, ///< abi.encodeBody() ABIEncodeData, ///< abi.encodeData() + ABIEncodeIntMsg, ///< abi.encodeIntMsg() ABIEncodeStateInit, ///< abi.encodeStateInit() ABIFunctionId, ///< abi.functionId(function_name) ABISetCodeSalt, ///< abi.setCodeSalt() @@ -1972,7 +1995,6 @@ class NullType: public Type Category category() const override { return Category::Null; } BoolResult isImplicitlyConvertibleTo(Type const& _other) const override; std::string richIdentifier() const override; - bool operator==(Type const& _other) const override; std::string toString(bool _short) const override; std::string canonicalName() const override; TypeResult interfaceType(bool) const override { return this; } @@ -1986,7 +2008,6 @@ class EmptyMapType: public Type Category category() const override { return Category::EmptyMap; } BoolResult isImplicitlyConvertibleTo(Type const& _other) const override; std::string richIdentifier() const override; - bool operator==(Type const& _other) const override; std::string toString(bool _short) const override; std::string canonicalName() const override; TypeResult interfaceType(bool) const override { return this; } @@ -2000,9 +2021,8 @@ class NanType: public Type Category category() const override { return Category::TVMNaN; } BoolResult isImplicitlyConvertibleTo(Type const& _other) const override; std::string richIdentifier() const override; - //bool operator==(Type const& _other) const override; std::string toString(bool _short) const override; - //std::string canonicalName() const override; + std::string canonicalName() const override; TypeResult interfaceType(bool) const override { return this; } TypeResult binaryOperatorResult(Token, Type const*) const override { return nullptr; } bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); } diff --git a/compiler/libsolidity/codegen/DictOperations.cpp b/compiler/libsolidity/codegen/DictOperations.cpp index 0903a25b..547e522f 100644 --- a/compiler/libsolidity/codegen/DictOperations.cpp +++ b/compiler/libsolidity/codegen/DictOperations.cpp @@ -30,8 +30,6 @@ DictOperation::DictOperation(StackPusher& pusher, Type const& keyType, Type cons void DictMinMax::minOrMax(bool saveOrigKeyAndNoTuple) { // stack: dict pusher.pushInt(dictKeyLength(&keyType)); // dict nbits - - const bool haveKey = true; bool isInRef = pusher.doesDictStoreValueInRef(&keyType, &valueType); dictOpcode = "DICT" + typeToDictChar(&keyType) + (isMin? "MIN" : "MAX") + (isInRef? "REF" : ""); @@ -40,7 +38,7 @@ void DictMinMax::minOrMax(bool saveOrigKeyAndNoTuple) { pusher.recoverKeyAndValueAfterDictOperation( &keyType, &valueType, - haveKey, + true, isInRef, StackPusher::DecodeType::DecodeValueOrPushNull, saveOrigKeyAndNoTuple diff --git a/compiler/libsolidity/codegen/TVMABI.cpp b/compiler/libsolidity/codegen/TVMABI.cpp index 53236a43..be762a55 100644 --- a/compiler/libsolidity/codegen/TVMABI.cpp +++ b/compiler/libsolidity/codegen/TVMABI.cpp @@ -75,7 +75,7 @@ Json::Value TVMABI::generateFunctionIdsJson( Json::Value TVMABI::generatePrivateFunctionIdsJson( ContractDefinition const& contract, - std::vector> _sourceUnits, + std::vector> const& _sourceUnits, PragmaDirectiveHelper const& pragmaHelper ) { Json::Value ids{Json::arrayValue}; @@ -99,25 +99,11 @@ Json::Value TVMABI::generateABIJson( std::vector const &pragmaDirectives ) { PragmaDirectiveHelper pdh{pragmaDirectives}; - TVMCompilerContext ctx(contract, pdh); - - const std::vector publicFunctions = TVMABI::publicFunctions(*contract); - std::vector events {}; - - for (const auto &_event : contract->definedInterfaceEvents()) - events.push_back(_event); - for (std::shared_ptr const& source: _sourceUnits) - for (ASTPointer const &node: source->nodes()) - if (auto lib = dynamic_cast(node.get())) - if (lib->isLibrary()) - for (const auto &event : lib->definedInterfaceEvents()) - events.push_back(event); - - std::set used; + TVMCompilerContext ctx{contract, pdh}; Json::Value root(Json::objectValue); root["ABI version"] = 2; - root["version"] = "2.4"; + root["version"] = "2.7"; // header { @@ -133,7 +119,9 @@ Json::Value TVMABI::generateABIJson( // functions { + std::set used; Json::Value functions(Json::arrayValue); + const std::vector publicFunctions = TVMABI::publicFunctions(*contract); for (FunctionDefinition const* f : publicFunctions) { auto funcName = TVMCompilerContext::getFunctionExternalName(f); if (used.count(funcName)) @@ -158,6 +146,16 @@ Json::Value TVMABI::generateABIJson( // events { + std::vector events {}; + for (const auto &_event : contract->definedInterfaceEvents()) + events.push_back(_event); + for (std::shared_ptr const& source: _sourceUnits) + for (ASTPointer const &node: source->nodes()) + if (auto lib = dynamic_cast(node.get())) + if (lib->isLibrary()) + for (const auto &event : lib->definedInterfaceEvents()) + events.push_back(event); + Json::Value eventAbi(Json::arrayValue); std::set usedEvents; for (const auto &e: events) { @@ -215,6 +213,20 @@ Json::Value TVMABI::generateABIJson( root["fields"] = fields; } + // getters + { + Json::Value functions(Json::arrayValue); + std::set used; + auto getters = TVMABI::getters(*contract); + for (FunctionDefinition const* f : getters) { + auto funcName = TVMCompilerContext::getFunctionExternalName(f); + solAssert(used.count(funcName) == 0, ""); + used.insert(funcName); + functions.append(toJson(funcName, convertArray(f->parameters()), convertArray(f->returnParameters()), f)); + } + root["getters"] = functions; + } + return root; } @@ -252,17 +264,17 @@ void TVMABI::generateABI( print(root["functions"], out); *out << "\t" << "],\n"; + *out << "\t" << R"("getters": [)" << "\n"; + print(root["getters"], out); + *out << "\t" << "],\n"; + *out << "\t" << R"("events": [)" << "\n"; print(root["events"], out); + *out << "\t" << "],\n"; - if (root.isMember("fields")) { - *out << "\t" << "],\n"; - *out << "\t" << R"("fields": [)" << "\n"; - printData(root["fields"], out); - *out << "\t" << "]\n"; - } else { - *out << "\t" << "]\n"; - } + *out << "\t" << R"("fields": [)" << "\n"; + printData(root["fields"], out); + *out << "\t" << "]\n"; *out << "}" << endl; } @@ -274,14 +286,32 @@ std::vector TVMABI::publicFunctions(ContractDefiniti for (auto c : contract.annotation().linearizedBaseContracts) { for (const auto &_function : c->definedFunctions()) { - if (!_function->isConstructor() && _function->isPublic() && - !_function->isReceive() && !_function->isFallback() && !_function->isOnBounce() && !_function->isOnTickTock()) + if (!_function->isConstructor() && + _function->isPublic() && + !_function->isReceive() && + !_function->isFallback() && + !_function->isOnBounce() && + !_function->isOnTickTock() && + _function->visibility() != Visibility::Getter + ) publicFunctions.push_back(_function); } } return publicFunctions; } +std::vector TVMABI::getters(ContractDefinition const& contract) { + std::vector getters; + for (auto c : contract.annotation().linearizedBaseContracts) { + for (const auto &_function : c->definedFunctions()) { + if (!_function->isConstructor() && + _function->visibility() == Visibility::Getter) + getters.push_back(_function); + } + } + return getters; +} + void TVMABI::printData(const Json::Value &json, std::ostream* out) { for (unsigned f = 0; f < json.size(); ++f) { const auto &element = json[f]; @@ -436,14 +466,16 @@ Json::Value TVMABI::setupNameTypeComponents(const string &name, const Type *type } else { const Type::Category category = type->category(); TypeInfo ti(type); - if (category == Type::Category::Address || category == Type::Category::Contract) { + if (category == Type::Category::Address || category == Type::Category::Contract) typeName = "address"; - } else if (category == Type::Category::VarInteger) { + else if (category == Type::Category::AddressStd) + typeName = "address_std"; + else if (category == Type::Category::VarInteger) { auto varint = to(type); typeName = varint->toString(false); - } else if (auto* fixedBytesType = to(type)) { + } else if (auto* fixedBytesType = to(type)) typeName = "fixedbytes" + toString(fixedBytesType->numBytes()); - } else if (ti.isNumeric) { + else if (ti.isNumeric) { if (to(type)) { typeName = "bool"; } else if (ti.isSigned) { @@ -635,21 +667,39 @@ void ChainDataDecoder::decodePublicFunctionParameters( *pusher << "ENDS"; } -void ChainDataDecoder::decodeFunctionParameters(const std::vector& types, bool isResponsible) { - pusher->startOpaque(); - pusher->pushS(1); - pusher->fixStack(-1); // fix stack +ChainDataDecoder::DecodeType ChainDataDecoder::getDecodeType(FunctionDefinition const* f) { + if (f->isExternalMsg()) + return DecodeType::ONLY_EXT_MSG; + if (f->isInternalMsg()) + return DecodeType::ONLY_INT_MSG; + return DecodeType::BOTH; +} - pusher->startContinuation(); - decodePublicFunctionParameters(types, isResponsible, false); - pusher->endContinuation(); +void ChainDataDecoder::decodeFunctionParameters(const std::vector& types, bool isResponsible, DecodeType decodeType) { + switch (decodeType) { + case DecodeType::ONLY_EXT_MSG: + decodePublicFunctionParameters(types, isResponsible, false); + break; + case DecodeType::ONLY_INT_MSG: + decodePublicFunctionParameters(types, isResponsible, true); + break; + case DecodeType::BOTH: + pusher->startOpaque(); + pusher->pushS(1); + pusher->fixStack(-1); // fix stack - pusher->startContinuation(); - decodePublicFunctionParameters(types, isResponsible, true); - pusher->endContinuation(); + pusher->startContinuation(); + decodePublicFunctionParameters(types, isResponsible, false); + pusher->endContinuation(); - pusher->ifElse(); - pusher->endOpaque(1, types.size()); + pusher->startContinuation(); + decodePublicFunctionParameters(types, isResponsible, true); + pusher->endContinuation(); + + pusher->ifElse(); + pusher->endOpaque(1, types.size()); + break; + } } void ChainDataDecoder::decodeData(int offset, int usedRefs, const std::vector& types) { @@ -744,7 +794,9 @@ void ChainDataDecoder::decodeParameter(Type const* type, DecodePosition* positio to(type) || to(type) || to(type) || - (category == Type::Category::Address || category == Type::Category::Contract) + category == Type::Category::Address || + category == Type::Category::Contract || + category == Type::Category::AddressStd ) { loadNextSliceIfNeed(position->loadNextCell(type)); pusher->load(type, false); @@ -764,7 +816,7 @@ void ChainDataDecoder::decodeParameterQ(Type const* type, DecodePosition* positi to(type) || to(type) || to(type) || - (category == Type::Category::Address || category == Type::Category::Contract) + (category == Type::Category::Address || category == Type::Category::AddressStd || category == Type::Category::Contract) ) { loadNextSliceIfNeed(position->loadNextCell(type)); pusher->loadQ(type); diff --git a/compiler/libsolidity/codegen/TVMABI.hpp b/compiler/libsolidity/codegen/TVMABI.hpp index 3e6324de..8efaa7ed 100644 --- a/compiler/libsolidity/codegen/TVMABI.hpp +++ b/compiler/libsolidity/codegen/TVMABI.hpp @@ -32,7 +32,7 @@ class TVMABI { ); static Json::Value generatePrivateFunctionIdsJson( ContractDefinition const& contract, - std::vector> _sourceUnits, + const std::vector>& _sourceUnits, PragmaDirectiveHelper const& pragmaHelper ); static void generateABI(ContractDefinition const* contract, @@ -43,6 +43,7 @@ class TVMABI { std::vector const& pragmaDirectives); private: static std::vector publicFunctions(ContractDefinition const& contract); + static std::vector getters(ContractDefinition const& contract); static void printData(const Json::Value& json, std::ostream* out); static void print(const Json::Value& json, std::ostream* out); static Json::Value toJson( @@ -95,7 +96,13 @@ class ChainDataDecoder : private boost::noncopyable { static int minBits(bool hasCallback); public: void decodePublicFunctionParameters(const std::vector& types, bool isResponsible, bool isInternal); - void decodeFunctionParameters(const std::vector& types, bool isResponsible); + enum class DecodeType { + ONLY_EXT_MSG, + ONLY_INT_MSG, + BOTH + }; + static DecodeType getDecodeType(FunctionDefinition const*); + void decodeFunctionParameters(const std::vector& types, bool isResponsible, DecodeType decodeType); void decodeData(int offset, int usedRefs, const std::vector& types); void decodeParameters( const std::vector& types, diff --git a/compiler/libsolidity/codegen/TVMAnalyzer.cpp b/compiler/libsolidity/codegen/TVMAnalyzer.cpp index 57da3686..3e42cdd2 100644 --- a/compiler/libsolidity/codegen/TVMAnalyzer.cpp +++ b/compiler/libsolidity/codegen/TVMAnalyzer.cpp @@ -69,7 +69,7 @@ bool TVMAnalyzer::visit(ContractDefinition const& contract) { for (EventDefinition const* event : contract.definedInterfaceEvents()) { if (used.count(event->name())) { m_errorReporter.declarationError( - 2018_error, + 5022_error, event->location(), SecondarySourceLocation().append("Another declaration is here:", used.at(event->name())->location()), "Event overriding is not supported." diff --git a/compiler/libsolidity/codegen/TVMCommons.cpp b/compiler/libsolidity/codegen/TVMCommons.cpp index 47e8c666..bb3bd44d 100644 --- a/compiler/libsolidity/codegen/TVMCommons.cpp +++ b/compiler/libsolidity/codegen/TVMCommons.cpp @@ -95,8 +95,8 @@ const Type *getType(const VariableDeclaration *var) { return var->annotation().type; } -bool isAddressOrContractType(const Type *type) { - return to(type) || to(type); +bool isAddressOrAddressStdOrContractType(const Type *type) { + return to(type) || to(type) || to(type); } bool isUsualArray(const Type *type) { @@ -169,7 +169,7 @@ std::string typeToDictChar(Type const *keyType) { } int dictKeyLength(Type const *key) { - if (isIn(key->category(), Type::Category::Address, Type::Category::Contract)) { + if (isIn(key->category(), Type::Category::Address, Type::Category::AddressStd, Type::Category::Contract)) { return AddressInfo::stdAddrWithoutAnyCastLength(); } @@ -332,6 +332,7 @@ getTupleTypes(TupleType const* tuple) { DictValueType toDictValueType(const Type::Category& category) { switch (category) { case Type::Category::Address: + case Type::Category::AddressStd: return DictValueType::Address; case Type::Category::Array: return DictValueType::Array; @@ -382,7 +383,10 @@ ABITypeSize::ABITypeSize(Type const* _type) { } void ABITypeSize::init(Type const* type) { - if (isAddressOrContractType(type)){ + if (type->category() == Type::Category::AddressStd) { + maxBits = 2 + (1 + 5 + 30) + 8 + 256; + maxRefs = 0; + } else if (isAddressOrAddressStdOrContractType(type)){ maxBits = AddressInfo::maxBitLength(); maxRefs = 0; } else if (isIntegralType(type)) { @@ -793,4 +797,29 @@ bool isFitUseless(Type const* left, Type const* right, Type const* common, Token ); } +// { width: 16, poly: 0x1021, init: 0x0000, refin: false, refout: false, +// xorout: 0x0000, check: 0x31c3, residue: 0x0000 }; +/* + Name : CRC-16 CCITT + Poly : 0x1021 x^16 + x^12 + x^5 + 1 + Init : 0x0000 + Revert: false + XorOut: 0x0000 + MaxLen: 4095 байт (32767 бит) +*/ +unsigned short crc16(char const *pcBlock, unsigned short len) +{ + unsigned short crc = 0; + unsigned char i; + + while (len--) + { + crc ^= (unsigned char)(*pcBlock++) << 8; + + for (i = 0; i < 8; i++) + crc = crc & 0x8000 ? (crc << 1) ^ 0x1021 : crc << 1; + } + return crc; +} + } // end namespace solidity::frontend diff --git a/compiler/libsolidity/codegen/TVMCommons.hpp b/compiler/libsolidity/codegen/TVMCommons.hpp index 121fd213..6ee937f9 100644 --- a/compiler/libsolidity/codegen/TVMCommons.hpp +++ b/compiler/libsolidity/codegen/TVMCommons.hpp @@ -52,7 +52,7 @@ constexpr uint64_t str2int(const char* str, int i = 0) { std::string functionName(FunctionDefinition const* _function); std::string eventName(EventDefinition const* _event); -bool isAddressOrContractType(const Type* type); +bool isAddressOrAddressStdOrContractType(const Type* type); bool isUsualArray(const Type* type); bool isByteArrayOrString(const Type* type); bool isString(const Type* type); @@ -268,7 +268,7 @@ std::pair, std::vector> getParams(const ast_vec& params, size_t offset = 0) { std::vector types; std::vector nodes; - for (auto it = params.begin() + offset; it != params.end(); it++) { + for (auto it = params.begin() + offset; it != params.end(); ++it) { types.push_back(getType(it->get())); nodes.push_back(it->get()); } @@ -406,4 +406,6 @@ namespace MathConsts { bool isFitUselessUnary(Type const* common, Token op); bool isFitUseless(Type const* left, Type const* right, Type const* common, Token op); +unsigned short crc16(char const *pcBlock, unsigned short len); + } // end solidity::frontend diff --git a/compiler/libsolidity/codegen/TVMContractCompiler.cpp b/compiler/libsolidity/codegen/TVMContractCompiler.cpp index 59ae3895..2a673193 100644 --- a/compiler/libsolidity/codegen/TVMContractCompiler.cpp +++ b/compiler/libsolidity/codegen/TVMContractCompiler.cpp @@ -99,6 +99,7 @@ TVMContractCompiler::generateContractCode( PragmaDirectiveHelper const &pragmaHelper ) { std::vector> functions; + std::map getters; TVMCompilerContext ctx{contract, pragmaHelper}; @@ -116,9 +117,9 @@ TVMContractCompiler::generateContractCode( for (FunctionDefinition const *_function : c->definedFunctions()) { if (_function->isConstructor() || !_function->isImplemented() || - _function->isInline()) { + _function->isInline() + ) continue; - } if (_function->isOnBounce()) { if (!ctx.isOnBounceGenerated()) { @@ -142,13 +143,20 @@ TVMContractCompiler::generateContractCode( functions.emplace_back(TVMFunctionCompiler::generateOnCodeUpgrade(ctx, _function)); } else { if (!ctx.isStdlib() && _function->isPublic() && !ctx.isBaseFunction(_function)) { - functions.emplace_back(TVMFunctionCompiler::generatePublicFunction(ctx, _function)); - - StackPusher pusher{&ctx}; - ChainDataEncoder encoder{&pusher}; - uint32_t functionId = encoder.calculateFunctionIDWithReason(_function, - ReasonOfOutboundMessage::RemoteCallInternal); - ctx.addPublicFunction(functionId, _function->name()); + if (_function->visibility() == Visibility::Getter) { + functions.emplace_back(TVMFunctionCompiler::generateGetterFunction(ctx, _function)); + uint32_t functionId = crc16(_function->name().c_str(), _function->name().length()); + functionId = (functionId & 0xffff) | 0x10000; + bool emplace = getters.emplace(functionId, _function->name()).second; + solAssert(emplace, ""); + } else { + functions.emplace_back(TVMFunctionCompiler::generatePublicFunction(ctx, _function)); + StackPusher pusher{&ctx}; + ChainDataEncoder encoder{&pusher}; + uint32_t functionId = encoder.calculateFunctionIDWithReason(_function, + ReasonOfOutboundMessage::RemoteCallInternal); + ctx.addPublicFunction(functionId, _function->name()); + } } auto const[functionName, id] = ctx.functionInternalName(_function); functions.emplace_back(TVMFunctionCompiler::generateFunction(ctx, _function, functionName, id)); @@ -274,9 +282,11 @@ TVMContractCompiler::generateContractCode( } Pointer c = createNode( - ctx.isStdlib(), ctx.getPragmaSaveAllFunctions(), pragmaHelper.hasUpgradeFunc(), pragmaHelper.hasUpgradeOldSol(), - std::string{"sol "} + solidity::frontend::VersionNumber, - functionOrder, ctx.callGraph().privateFunctions() + ctx.isStdlib(), ctx.getPragmaSaveAllFunctions(), pragmaHelper.hasUpgradeFunc(), pragmaHelper.hasUpgradeOldSol(), + std::string{"sol "} + solidity::frontend::VersionNumber, + functionOrder, + ctx.callGraph().privateFunctions(), + getters ); DeleterAfterRet d; @@ -333,23 +343,23 @@ void TVMContractCompiler::optimizeCode(Pointer& c) { } void TVMContractCompiler::fillInlineFunctions(TVMCompilerContext &ctx, ContractDefinition const *contract) { - std::map inlineFunctions; + std::set inlineFunctions; for (ContractDefinition const *base : contract->annotation().linearizedBaseContracts | boost::adaptors::reversed) { for (FunctionDefinition const *function : base->definedFunctions()) { if (function->isInline()) { - inlineFunctions[functionName(function)] = function; + inlineFunctions.insert(function); } } } TVMInlineFunctionChecker inlineFunctionChecker; - for (FunctionDefinition const *function : inlineFunctions | boost::adaptors::map_values) { + for (FunctionDefinition const *function : inlineFunctions) { function->accept(inlineFunctionChecker); } std::vector order = inlineFunctionChecker.functionOrder(); for (FunctionDefinition const * function : order) { - const std::string name = functionName(function); + const std::string name = ctx.functionInternalName(function).first; ctx.setCurrentFunction(function, name); StackPusher pusher{&ctx}; TVMFunctionCompiler::generateFunctionWithModifiers(pusher, function, true); diff --git a/compiler/libsolidity/codegen/TVMExpressionCompiler.cpp b/compiler/libsolidity/codegen/TVMExpressionCompiler.cpp index 853d58a4..a65a2130 100644 --- a/compiler/libsolidity/codegen/TVMExpressionCompiler.cpp +++ b/compiler/libsolidity/codegen/TVMExpressionCompiler.cpp @@ -617,7 +617,7 @@ void TVMExpressionCompiler::visit2(BinaryOperation const &_binaryOperation) { return; } - if (isAddressOrContractType(lt) || isAddressOrContractType(rt) || (isSlice(lt) && isSlice(rt))) { + if (isAddressOrAddressStdOrContractType(lt) || isAddressOrAddressStdOrContractType(rt) || (isSlice(lt) && isSlice(rt))) { acceptLeft(); acceptRight(); compareSlices(op); @@ -980,7 +980,8 @@ void TVMExpressionCompiler::visit2(MemberAccess const &_node) { if (category == Type::Category::Magic) { return visitMagic(_node); } - if (checkForAddressMemberAccess(_node, category)) { + if (isIn(category, Type::Category::Address, Type::Category::AddressStd)) { + checkForAddressMemberAccess(_node); return; } @@ -993,7 +994,7 @@ void TVMExpressionCompiler::visit2(MemberAccess const &_node) { if (category == Type::Category::TypeType) { auto typeType = to(_node.expression().annotation().type); auto actualType = typeType->actualType(); - if (actualType->category() == Type::Category::Address) { + if (isIn(actualType->category(), Type::Category::Address, Type::Category::AddressStd)) { solAssert(memberName == "addrNone", ""); m_pusher.pushSlice("x2_"); return; @@ -1023,16 +1024,13 @@ void TVMExpressionCompiler::visit2(MemberAccess const &_node) { cast_error(_node, "Not supported."); } -bool TVMExpressionCompiler::checkForAddressMemberAccess(MemberAccess const &_node, Type::Category category) { - if (category != Type::Category::Address) - return false; +void TVMExpressionCompiler::checkForAddressMemberAccess(MemberAccess const &_node) { if (_node.memberName() == "balance") { if (!isAddressThis(to(&_node.expression()))) { cast_error(_node.expression(), "Only 'address(this).balance' is supported for member balance"); } m_pusher << "GETPARAM 7"; m_pusher.indexNoexcep(0); - return true; } if (_node.memberName() == "currencies") { if (!isAddressThis(to(&_node.expression()))) { @@ -1040,22 +1038,18 @@ bool TVMExpressionCompiler::checkForAddressMemberAccess(MemberAccess const &_nod } m_pusher << "GETPARAM 7"; m_pusher.indexNoexcep(1); - return true; } if (_node.memberName() == "wid") { compileNewExpr(&_node.expression()); m_pusher << "PARSEMSGADDR"; m_pusher.indexWithExcep(2); - return true; } if (_node.memberName() == "value") { compileNewExpr(&_node.expression()); m_pusher << "PARSEMSGADDR"; m_pusher.indexWithExcep(3); m_pusher << "PLDU 256"; - return true; } - return false; } void TVMExpressionCompiler::visitMemberAccessArray(MemberAccess const &_node) { diff --git a/compiler/libsolidity/codegen/TVMExpressionCompiler.hpp b/compiler/libsolidity/codegen/TVMExpressionCompiler.hpp index 366570bf..2ce76043 100644 --- a/compiler/libsolidity/codegen/TVMExpressionCompiler.hpp +++ b/compiler/libsolidity/codegen/TVMExpressionCompiler.hpp @@ -77,7 +77,7 @@ class TVMExpressionCompiler { void visitMsgMagic(MemberAccess const& _node); void visitMagic(MemberAccess const& _node); void visit2(MemberAccess const& _node); - bool checkForAddressMemberAccess(MemberAccess const& _node, Type::Category category); + void checkForAddressMemberAccess(MemberAccess const& _node); void visitMemberAccessArray(MemberAccess const& _node); void visitMemberAccessFixedBytes(MemberAccess const& _node, FixedBytesType const* fbt); static void indexTypeCheck(IndexAccess const& _node); diff --git a/compiler/libsolidity/codegen/TVMFunctionCall.cpp b/compiler/libsolidity/codegen/TVMFunctionCall.cpp index 5d807012..a6468a5d 100644 --- a/compiler/libsolidity/codegen/TVMFunctionCall.cpp +++ b/compiler/libsolidity/codegen/TVMFunctionCall.cpp @@ -118,7 +118,7 @@ void FunctionCallCompiler::compile() { { // nothing } else if (category == Type::Category::Magic && ident != nullptr && ident->name() == "tvm") { - if (m_funcType->kind() == FunctionType::Kind::ABIBuildIntMsg) { + if (m_funcType->kind() == FunctionType::Kind::ABIEncodeIntMsg) { abiBuildIntMsg(); } else if (m_funcType->kind() == FunctionType::Kind::ABIEncodeData) { abiBuildDataInit(); @@ -145,7 +145,7 @@ void FunctionCallCompiler::compile() { abiDecodeData(); else if (m_funcType->kind() == FunctionType::Kind::ABIEncodeBody) abiEncodeBody(); - else if (m_funcType->kind() == FunctionType::Kind::ABIBuildIntMsg) + else if (m_funcType->kind() == FunctionType::Kind::ABIEncodeIntMsg) abiBuildIntMsg(); else if (m_funcType->kind() == FunctionType::Kind::ABIEncodeData) abiBuildDataInit(); @@ -153,7 +153,7 @@ void FunctionCallCompiler::compile() { abiFunction(); } else if (category == Type::Category::Magic && ident != nullptr && ident->name() == "math") { mathFunction(*m_memberAccess); - } else if (category == Type::Category::Address) { + } else if (isIn(category, Type::Category::Address, Type::Category::AddressStd)) { addressMethod(); } else if (category == Type::Category::TvmCell) { cellMethods(*m_memberAccess); @@ -169,7 +169,7 @@ void FunctionCallCompiler::compile() { // nothing } else if (to(actualType)) { userDefinedValueMethods(*m_memberAccess); - } else if (to(actualType)) { + } else if (to(actualType) || to(actualType)) { addressMethods(*m_memberAccess); } else { reportError(); @@ -3152,6 +3152,7 @@ void FunctionCallCompiler::typeConversion() { } break; case Type::Category::Address: + case Type::Category::AddressStd: case Type::Category::Contract: case Type::Category::FixedBytes: case Type::Category::Array: @@ -3164,12 +3165,12 @@ void FunctionCallCompiler::typeConversion() { } bool FunctionCallCompiler::checkLocalFunctionOrLibCall(const Identifier *identifier) { - const string& functionName = identifier->name(); auto functionDefinition = to(identifier->annotation().referencedDeclaration); if (!functionDefinition) return false; pushArgs(); if (functionDefinition->isInline()) { + const string& functionName = m_pusher.ctx().functionInternalName(functionDefinition, false).first; int take = m_funcType->parameterTypes().size(); int ret = m_funcType->returnParameterTypes().size(); m_pusher.pushInlineFunction(functionName, take, ret); @@ -3349,7 +3350,8 @@ bool FunctionCallCompiler::checkSolidityUnits() { } std::string format = formatStr.substr(pos + 1, close_pos - pos - 1); - if (format[0] == ':') format.erase(0, 1); + if (format[0] == ':') + format.erase(0, 1); substrings.emplace_back(formatStr.substr(0, pos), format); formatStr = formatStr.substr(close_pos + 1); pos = 0; @@ -3380,17 +3382,23 @@ bool FunctionCallCompiler::checkSolidityUnits() { if (cat == Type::Category::Integer || cat == Type::Category::RationalNumber) { // stack: Stack(TvmBuilder) std::string format = substrings[it].second; - bool leadingZeroes = !format.empty() && (format[0] == '0'); + bool leadingZeroes = !format.empty() && format[0] == '0'; bool isHex = !format.empty() && (format.back() == 'x' || format.back() == 'X'); - bool isLower = isHex && (format.back() == 'x'); + bool isLower = isHex && !format.empty() && format.back() == 'x'; bool isTon = !format.empty() && format.back() == 't'; if (!isTon) { while (!format.empty() && (format.back() < '0' || format.back() > '9')) { - format.erase(format.size() - 1, 1); + format.pop_back(); } int width = 0; - if (!format.empty()) - width = std::stoi(format); + if (!format.empty()) { + try { + width = boost::lexical_cast(format); + } catch (boost::bad_lexical_cast const&) { + cast_error(*m_arguments[0], "Invalid format width." + " Can not convert \"" + format + "\" to integer."); + } + } if (width < 0 || width > 127) cast_error(m_functionCall, "Width should be in range of 0 to 127."); // stack: stack x @@ -3411,7 +3419,7 @@ bool FunctionCallCompiler::checkSolidityUnits() { m_pusher.pushInt(MathConsts::power10().at(9)); m_pusher.pushFragmentInCallRef(4, 1, "__convertFixedPointToString"); } - } else if (cat == Type::Category::Address) { + } else if (cat == Type::Category::Address || cat == Type::Category::AddressStd) { m_pusher.pushFragmentInCallRef(2, 1, "__convertAddressToHexString"); } else if (isStringOrStringLiteralOrBytes(argType)) { m_pusher.pushFragmentInCallRef(2, 1, "__appendStringToStringBuilder"); diff --git a/compiler/libsolidity/codegen/TVMFunctionCompiler.cpp b/compiler/libsolidity/codegen/TVMFunctionCompiler.cpp index 3859699b..30db6ce6 100644 --- a/compiler/libsolidity/codegen/TVMFunctionCompiler.cpp +++ b/compiler/libsolidity/codegen/TVMFunctionCompiler.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -337,7 +338,7 @@ void TVMFunctionCompiler::decodeFunctionParamsAndInitVars(bool isResponsible) { // decode function params // stack: arguments-in-slice vector types = getParams(m_function->parameters()).first; - ChainDataDecoder{&m_pusher}.decodeFunctionParameters(types, isResponsible); + ChainDataDecoder{&m_pusher}.decodeFunctionParameters(types, isResponsible, ChainDataDecoder::getDecodeType(m_function)); // stack: transaction_id arguments... m_pusher.getStack().change(-static_cast(m_function->parameters().size())); for (const ASTPointer& variable: m_function->parameters()) { @@ -405,6 +406,27 @@ TVMFunctionCompiler::generatePublicFunction(TVMCompilerContext& ctx, FunctionDef return createNode(3, 0, name, nullopt, type, block); } +Pointer +TVMFunctionCompiler::generateGetterFunction(TVMCompilerContext& ctx, FunctionDefinition const* function) { + // stack: function params + std::string name = function->name(); + ctx.setCurrentFunction(function, name); + + StackPusher pusher{&ctx}; + + pusher.startOpaque(); + pusher.pushFragmentInCallRef(0, 0, "c4_to_c7"); + int paramQty = function->parameters().size(); + int retQty = function->returnParameters().size(); + pusher.pushFragmentInCallRef(paramQty, retQty, pusher.ctx().functionInternalName(function).first); + pusher.endOpaque(0, 0); + + Pointer block = pusher.getBlock(); + ctx.resetCurrentFunction(); + + return createNode(3, 0, name, nullopt, Function::FunctionType::Fragment, block); +} + void TVMFunctionCompiler::generateFunctionWithModifiers( StackPusher& pusher, FunctionDefinition const* function, @@ -539,22 +561,22 @@ void TVMFunctionCompiler::emitOnPublicFunctionReturn() { ret = convertArray(m_function->returnParameters()); } - m_pusher.pushS(m_pusher.stackSize()); - m_pusher.fixStack(-1); // fix stack + bool isResponsible = m_pusher.ctx().currentFunction()->isResponsible(); + auto appendBodyForExtMsg = [&](int builderSize) { + ChainDataEncoder{&m_pusher}.createMsgBodyAndAppendToBuilder( + ret, + ChainDataEncoder{&m_pusher}.calculateFunctionIDWithReason(m_function, ReasonOfOutboundMessage::FunctionReturnExternal), + {}, + builderSize + ); + }; + m_pusher.pushS(m_pusher.stackSize()); // push selector: ext or int msg + m_pusher.fixStack(-1); // fix stack // emit for ext m_pusher.startContinuation(); { - auto appendBody = [&](int builderSize) { - ChainDataEncoder{&m_pusher}.createMsgBodyAndAppendToBuilder( - ret, - ChainDataEncoder{&m_pusher}.calculateFunctionIDWithReason(m_function, - ReasonOfOutboundMessage::FunctionReturnExternal), - {}, - builderSize - ); - }; // ext_in_msg_info$10 src:MsgAddressExt dest:MsgAddressInt // import_fee:Grams = CommonMsgInfo; @@ -570,7 +592,7 @@ void TVMFunctionCompiler::emitOnPublicFunctionReturn() { m_pusher.sendMsg( {TvmConst::ext_msg_info::dest}, {}, - appendBody, + appendBodyForExtMsg, nullptr, nullptr, StackPusher::MsgType::ExternalOut @@ -578,8 +600,6 @@ void TVMFunctionCompiler::emitOnPublicFunctionReturn() { m_pusher.fixStack(params.size()); // fix stack } m_pusher.endContinuation(); - - m_pusher.startContinuation(); if (!isResponsible) { m_pusher.drop(params.size()); @@ -629,12 +649,11 @@ void TVMFunctionCompiler::emitOnPublicFunctionReturn() { ); } m_pusher.endContinuation(); - m_pusher.ifElse(); m_pusher.endOpaque(ret.size(), 0); - solAssert(stackSize == int(m_pusher.stackSize()) + int(params.size()), ""); + m_pusher.ensureSize(stackSize - int(params.size())); } void TVMFunctionCompiler::visitModifierOrFunctionBlock(Block const &body, int argQty, int retQty, int nameRetQty) { @@ -1127,7 +1146,7 @@ bool TVMFunctionCompiler::visit(ForEachStatement const& _forStatement) { // For bytes: // // cell - // [return flag] - optional. If have return/break/continue. + // [return flag] - optional. If we have return/break/continue. // For array: // @@ -1260,7 +1279,8 @@ bool TVMFunctionCompiler::visit(ForEachStatement const& _forStatement) { // stack: cell value [flag] solAssert(ss == m_pusher.stackSize(), ""); - } + } else if (optValueAsTuple(arrayType->baseType())) + m_pusher.untuple(1); } }; std::function pushLoopExpression = [&]() { @@ -1617,7 +1637,8 @@ Pointer TVMFunctionCompiler::generateMainExternal( if (pusher.ctx().afterSignatureCheck()) { // ... msg_cell msg_body_slice -1 rest_msg_body_slice pusher.pushS(3); - pusher.pushInlineFunction("afterSignatureCheck", 2, 1); + auto const name = pusher.ctx().functionInternalName(pusher.ctx().afterSignatureCheck()).first; + pusher.pushInlineFunction(name, 2, 1); } else { if (pusher.ctx().pragmaHelper().hasTime()) f.defaultReplayProtection(); @@ -2041,7 +2062,7 @@ Pointer TVMConstructorCompiler::generateConstructors() { } else { take = constructor->parameters().size(); vector types = getParams(constructor->parameters()).first; - ChainDataDecoder{&m_pusher}.decodeFunctionParameters(types, false); + ChainDataDecoder{&m_pusher}.decodeFunctionParameters(types, false, ChainDataDecoder::getDecodeType(constructor)); m_pusher.getStack().change(-static_cast(constructor->parameters().size())); for (const ASTPointer& variable: constructor->parameters()) m_pusher.getStack().add(variable.get(), true); diff --git a/compiler/libsolidity/codegen/TVMFunctionCompiler.hpp b/compiler/libsolidity/codegen/TVMFunctionCompiler.hpp index bfc74787..8ace7947 100644 --- a/compiler/libsolidity/codegen/TVMFunctionCompiler.hpp +++ b/compiler/libsolidity/codegen/TVMFunctionCompiler.hpp @@ -54,6 +54,7 @@ class TVMFunctionCompiler: public ASTConstVisitor, private boost::noncopyable static Pointer generateFallback(TVMCompilerContext& ctx, FunctionDefinition const* function); static Pointer generateOnBounce(TVMCompilerContext& ctx, FunctionDefinition const* function); static Pointer generatePublicFunction(TVMCompilerContext& ctx, FunctionDefinition const* function); + static Pointer generateGetterFunction(TVMCompilerContext& ctx, FunctionDefinition const* function); static void generateFunctionWithModifiers(StackPusher& pusher, FunctionDefinition const* function, bool pushArgs); static Pointer generateGetter(StackPusher& pusher, VariableDeclaration const* vd); static Pointer generatePublicFunctionSelector(TVMCompilerContext& pusher, ContractDefinition const *contract); diff --git a/compiler/libsolidity/codegen/TVMPusher.cpp b/compiler/libsolidity/codegen/TVMPusher.cpp index 1c9f7b8a..0c31da4c 100644 --- a/compiler/libsolidity/codegen/TVMPusher.cpp +++ b/compiler/libsolidity/codegen/TVMPusher.cpp @@ -283,12 +283,10 @@ bool StackPusher::doesDictStoreValueInRef(Type const* keyType, Type const* value solUnimplemented(""); } -// false - value isn't in ref -// true - value is in ref void StackPusher::recoverKeyAndValueAfterDictOperation( Type const* keyType, Type const* valueType, - bool haveKey, + bool hasKey, bool didUseOpcodeWithRef, const DecodeType& decodeType, bool saveOrigKeyAndNoTuple @@ -302,10 +300,10 @@ void StackPusher::recoverKeyAndValueAfterDictOperation( // stack: value [key] auto preloadValue = [&]() { - if (haveKey) { + if (hasKey) { // stack: value key if (saveOrigKeyAndNoTuple) { - pushS(0); // stack: value key key + pushS(0); // stack: value key [key] } if (keyType->category() == Type::Category::Struct) { StructCompiler sc{this, to(keyType)}; @@ -420,7 +418,7 @@ void StackPusher::recoverKeyAndValueAfterDictOperation( startContinuation(); preloadValue(); - if (haveKey) { + if (hasKey) { if (!saveOrigKeyAndNoTuple) { makeTuple(2); } @@ -505,7 +503,7 @@ bool StackPusher::tryPollEmptyPushCont() { return false; } -TVMCompilerContext &StackPusher::ctx() { +TVMCompilerContext &StackPusher::ctx() const { return *m_ctx; } @@ -1140,6 +1138,7 @@ bool StackPusher::fastLoad(const Type* type) { } case Type::Category::Address: case Type::Category::Contract: + case Type::Category::AddressStd: *this << "LDMSGADDR"; return true; case Type::Category::Enum: @@ -1213,14 +1212,6 @@ void StackPusher::preload(const Type *type) { drop(); break; } - case Type::Category::Address: - case Type::Category::Contract: - *this << "LDMSGADDR"; - drop(1); - break; - case Type::Category::TvmCell: - *this << "PLDREF"; - break; case Type::Category::Struct: { auto structType = to(type); StructCompiler sc{this, structType}; @@ -1309,6 +1300,7 @@ void StackPusher::loadQ(const Type *type) { break; } case Type::Category::Address: + case Type::Category::AddressStd: case Type::Category::Contract: pushAsym("LDMSGADDRQ"); break; @@ -1412,7 +1404,7 @@ void StackPusher::store(const Type *type) { startContinuation(); // builder value - if (isIn(optType->valueType()->category(), Type::Category::Optional, Type::Category::Mapping)) { + if (optValueAsTuple(optType->valueType())) { untuple(1); } // builder value @@ -1460,6 +1452,7 @@ void StackPusher::store(const Type *type) { break; } case Type::Category::Address: + case Type::Category::AddressStd: case Type::Category::Contract: case Type::Category::TvmSlice: *this << "STSLICE"; // builder slice-value @@ -1548,6 +1541,7 @@ void StackPusher::storeQ(const Type *type) { pushAsym("STREFQ"); break; case Type::Category::Address: + case Type::Category::AddressStd: case Type::Category::Contract: case Type::Category::TvmSlice: pushAsym("STSLICEQ"); @@ -1663,7 +1657,7 @@ void StackPusher::pushFragmentInCallRef(int take, int ret, const std::string &fu void StackPusher::pushCallOrCallRef( FunctionDefinition const* _functionDef, const std::optional>& deltaStack, - bool isCalledByPoint + const bool isCalledByPoint ) { auto [take, ret] = deltaStack.has_value() ? deltaStack.value() : @@ -2009,7 +2003,7 @@ void StackPusher::prepareMsg( appendBody(msgInfoSize); // stack: builder-with-body } else { - appendToBuilder("0"); // there is no body + appendToBuilder("0"); // there is no message body } // stack: builder' @@ -2350,6 +2344,7 @@ void StackPusher::pushDefaultValue(Type const* _type) { switch (cat) { case Type::Category::Address: case Type::Category::Contract: + case Type::Category::AddressStd: pushSlice("x2_"); // addr_none$00 = MsgAddressExt; break; case Type::Category::Bool: @@ -2541,6 +2536,7 @@ void TypeConversion::convert(Type const* leftType, Type const* rightType) { fromStringLiteral(leftType, to(rightType)); break; case Type::Category::Address: + case Type::Category::AddressStd: case Type::Category::Bool: case Type::Category::Contract: case Type::Category::EmptyMap: @@ -2564,7 +2560,7 @@ void TypeConversion::convert(Type const* leftType, Type const* rightType) { } } -void TypeConversion::integerToInteger(IntegerType const* leftType, IntegerType const* rightType) { +void TypeConversion::integerToInteger(IntegerType const* leftType, IntegerType const* rightType) const { if (rightType->isImplicitlyConvertibleTo(*leftType)) return ; @@ -2591,7 +2587,7 @@ void TypeConversion::integerToInteger(IntegerType const* leftType, IntegerType c } } -void TypeConversion::fixedPointToInteger(IntegerType const* leftType, FixedPointType const* rightType) { +void TypeConversion::fixedPointToInteger(IntegerType const* leftType, FixedPointType const* rightType) const { int powerDiff = rightType->fractionalDigits(); if (powerDiff > 0) { m_pusher.pushInt(MathConsts::power10().at(powerDiff)); @@ -2600,7 +2596,7 @@ void TypeConversion::fixedPointToInteger(IntegerType const* leftType, FixedPoint integerToInteger(leftType, rightType->asIntegerType()); } -void TypeConversion::fixedPointToFixedPoint(FixedPointType const* leftType, FixedPointType const* rightType) { +void TypeConversion::fixedPointToFixedPoint(FixedPointType const* leftType, FixedPointType const* rightType) const { int powerDiff = leftType->fractionalDigits() - rightType->fractionalDigits(); if (powerDiff != 0) { if (powerDiff > 0) { @@ -2614,7 +2610,7 @@ void TypeConversion::fixedPointToFixedPoint(FixedPointType const* leftType, Fixe integerToInteger(leftType->asIntegerType(), rightType->asIntegerType()); } -void TypeConversion::integerToFixedPoint(FixedPointType const* leftType, IntegerType const* rightType) { +void TypeConversion::integerToFixedPoint(FixedPointType const* leftType, IntegerType const* rightType) const { int powerDiff = leftType->fractionalDigits(); if (powerDiff > 0) { m_pusher.pushInt(MathConsts::power10().at(powerDiff)); @@ -2623,7 +2619,7 @@ void TypeConversion::integerToFixedPoint(FixedPointType const* leftType, Integer integerToInteger(leftType->asIntegerType(), rightType); } -void TypeConversion::fixedBytesToFixedBytes(FixedBytesType const* leftType, FixedBytesType const* rightType) { +void TypeConversion::fixedBytesToFixedBytes(FixedBytesType const* leftType, FixedBytesType const* rightType) const { int diff = 8 * (leftType->numBytes() - rightType->numBytes()); if (diff > 0) { m_pusher << "LSHIFT " + std::to_string(diff); @@ -2632,7 +2628,7 @@ void TypeConversion::fixedBytesToFixedBytes(FixedBytesType const* leftType, Fixe } } -void TypeConversion::bytesToFixedBytes(FixedBytesType const* rightType) { +auto TypeConversion::bytesToFixedBytes(FixedBytesType const *rightType) const -> void { size_t bits = rightType->numBytes() * 8; m_pusher.startContinuation(); m_pusher.startOpaque(); @@ -2670,11 +2666,12 @@ void TypeConversion::bytesToFixedBytes(FixedBytesType const* rightType) { m_pusher.pushRefContAndCallX(1, 1, false); } -void TypeConversion::stringLiteralToFixedBytes(FixedBytesType const* leftType, StringLiteralType const* rightType) { +void TypeConversion::stringLiteralToFixedBytes(FixedBytesType const* leftType, StringLiteralType const* rightType) const { size_t bytes = 0; u256 value = 0; for (char c : rightType->value()) { - value = value * 256 + c; + auto x = static_cast(c); + value = value * 256 + x; ++bytes; } while (bytes < leftType->numBytes()) { @@ -2685,7 +2682,7 @@ void TypeConversion::stringLiteralToFixedBytes(FixedBytesType const* leftType, S m_pusher << "PUSHINT " + toString(value); } -void TypeConversion::fromFixedPoint(Type const* leftType, FixedPointType const* rightType) { +void TypeConversion::fromFixedPoint(Type const* leftType, FixedPointType const* rightType) const { switch (leftType->category()) { case Type::Category::FixedPoint: fixedPointToFixedPoint(to(leftType), rightType); @@ -2702,7 +2699,7 @@ void TypeConversion::fromFixedPoint(Type const* leftType, FixedPointType const* } } -void TypeConversion::convertIntegerToAddress(Type const* t) { +void TypeConversion::convertIntegerToAddress(Type const* t) const { if (auto r = to(t)) { m_pusher.drop(); m_pusher.pushSlice("x" + StrUtils::binaryStringToSlice(StrUtils::literalToSliceAddress(r->value2()))); @@ -2715,13 +2712,13 @@ void TypeConversion::convertIntegerToAddress(Type const* t) { } } -void TypeConversion::convertIntegerToEnum(EnumType const* leftType, IntegerType const* /*rightType*/) { +void TypeConversion::convertIntegerToEnum(EnumType const* leftType, IntegerType const* /*rightType*/) const { int const size = leftType->enumDefinition().members().size(); m_pusher.pushInt(size); m_pusher << "MOD"; } -void TypeConversion::fromInteger(Type const* leftType, IntegerType const* rightType) { +void TypeConversion::fromInteger(Type const* leftType, IntegerType const* rightType) const { switch (leftType->category()) { case Type::Category::FixedPoint: integerToFixedPoint(to(leftType), rightType); @@ -2743,6 +2740,7 @@ void TypeConversion::fromInteger(Type const* leftType, IntegerType const* rightT // do nothing here break; case Type::Category::Address: + case Type::Category::AddressStd: case Type::Category::Contract: convertIntegerToAddress(rightType); break; @@ -2755,7 +2753,7 @@ void TypeConversion::fromInteger(Type const* leftType, IntegerType const* rightT } } -void TypeConversion::fromRational(Type const* leftType, RationalNumberType const* rightType) { +void TypeConversion::fromRational(Type const* leftType, RationalNumberType const* rightType) const { switch (leftType->category()) { case Type::Category::FixedPoint: { auto fixedPointLeft = to(leftType); @@ -2782,6 +2780,7 @@ void TypeConversion::fromRational(Type const* leftType, RationalNumberType const // do nothing here break; case Type::Category::Address: + case Type::Category::AddressStd: case Type::Category::Contract: convertIntegerToAddress(rightType); break; @@ -2804,12 +2803,12 @@ void TypeConversion::tupleFromTuple(TupleType const* leftType, TupleType const* } } -void TypeConversion::fromFixedBytesType(Type const* leftType, FixedBytesType const* rightType) { +void TypeConversion::fromFixedBytesType(Type const* leftType, FixedBytesType const* rightType) const { switch (leftType->category()) { - case Type::Category::Address: { + case Type::Category::Address: + case Type::Category::AddressStd: convertIntegerToAddress(rightType); break; - } case Type::Category::FixedBytes: { fixedBytesToFixedBytes(to(leftType), rightType); break; @@ -2841,7 +2840,7 @@ void TypeConversion::fromFixedBytesType(Type const* leftType, FixedBytesType con } } -void TypeConversion::fromArray(Type const* leftType, ArrayType const* rightType) { +void TypeConversion::fromArray(Type const* leftType, ArrayType const* rightType) const { auto r = to(rightType); if (!r->isByteArrayOrString()) { return; @@ -2895,7 +2894,7 @@ void TypeConversion::fromOptional(Type const* leftType, OptionalType const* righ } } -void TypeConversion::fromSlice(Type const* leftType) { +void TypeConversion::fromSlice(Type const* leftType) const { switch (leftType->category()) { case Type::Category::TvmSlice: break; @@ -2923,7 +2922,7 @@ void TypeConversion::fromTuple(Type const* leftType, TupleType const* rightType) } } -void TypeConversion::fromStringLiteral(Type const* leftType, StringLiteralType const* rightType) { +void TypeConversion::fromStringLiteral(Type const* leftType, StringLiteralType const* rightType) const { switch (leftType->category()) { case Type::Category::FixedBytes: stringLiteralToFixedBytes(to(leftType), rightType); diff --git a/compiler/libsolidity/codegen/TVMPusher.hpp b/compiler/libsolidity/codegen/TVMPusher.hpp index ed687ea6..f50bb9cf 100644 --- a/compiler/libsolidity/codegen/TVMPusher.hpp +++ b/compiler/libsolidity/codegen/TVMPusher.hpp @@ -104,7 +104,7 @@ class TVMCompilerContext { m_currentFunction = _f; m_currentFunctionName = _name; } - FunctionDefinition const* currentFunction() { return m_currentFunction; } + FunctionDefinition const* currentFunction() const { return m_currentFunction; } std::string currentFunctionName() { return m_currentFunctionName.value(); } void resetCurrentFunction() { m_currentFunction = nullptr; @@ -181,7 +181,7 @@ class StackPusher { bool tryPollEmptyPushCont(); [[nodiscard]] - TVMCompilerContext& ctx(); + TVMCompilerContext& ctx() const; private: void change(int delta); void change(int take, int ret); @@ -317,7 +317,7 @@ class StackPusher { DataType prepareValueForDictOperations(Type const* keyType, Type const* valueType); [[nodiscard]] DataType pushDefaultValueForDict(Type const* keyType, Type const* valueType); - bool doesDictStoreValueInRef(Type const* keyType, Type const* valueType); + static bool doesDictStoreValueInRef(Type const* keyType, Type const* valueType); enum class DecodeType { DecodeValue, @@ -329,7 +329,7 @@ class StackPusher { void recoverKeyAndValueAfterDictOperation( Type const* keyType, Type const* valueType, - bool haveKey, + bool hasKey, bool didUseOpcodeWithRef, const DecodeType& decodeType, bool saveOrigKeyAndNoTuple = false @@ -412,25 +412,25 @@ class TypeConversion { TypeConversion(StackPusher& _pusher) : m_pusher{_pusher} { } void convert(Type const* leftType, Type const* rightType); private: - void integerToInteger(IntegerType const* leftType, IntegerType const* rightType); - void fixedPointToInteger(IntegerType const* leftType, FixedPointType const* rightType); - void fixedPointToFixedPoint(FixedPointType const* leftType, FixedPointType const* rightType); - void integerToFixedPoint(FixedPointType const* leftType, IntegerType const* rightType); - void fixedBytesToFixedBytes(FixedBytesType const* leftType, FixedBytesType const* rightType); - void bytesToFixedBytes(FixedBytesType const* rightType); - void stringLiteralToFixedBytes(FixedBytesType const* leftType, StringLiteralType const* rightType); - void fromFixedPoint(Type const* leftType, FixedPointType const* rightType); - void convertIntegerToAddress(Type const* t); - void convertIntegerToEnum(EnumType const* leftType, IntegerType const* rightType); - void fromInteger(Type const* leftType, IntegerType const* rightType); - void fromRational(Type const* leftType, RationalNumberType const* rightType); + void integerToInteger(IntegerType const* leftType, IntegerType const* rightType) const; + void fixedPointToInteger(IntegerType const* leftType, FixedPointType const* rightType) const; + void fixedPointToFixedPoint(FixedPointType const* leftType, FixedPointType const* rightType) const; + void integerToFixedPoint(FixedPointType const* leftType, IntegerType const* rightType) const; + void fixedBytesToFixedBytes(FixedBytesType const* leftType, FixedBytesType const* rightType) const; + void bytesToFixedBytes(FixedBytesType const* rightType) const; + void stringLiteralToFixedBytes(FixedBytesType const* leftType, StringLiteralType const* rightType) const; + void fromFixedPoint(Type const* leftType, FixedPointType const* rightType) const; + void convertIntegerToAddress(Type const* t) const; + void convertIntegerToEnum(EnumType const* leftType, IntegerType const* rightType) const; + void fromInteger(Type const* leftType, IntegerType const* rightType) const; + void fromRational(Type const* leftType, RationalNumberType const* rightType) const; void tupleFromTuple(TupleType const* leftType, TupleType const* rightType); - void fromFixedBytesType(Type const* leftType, FixedBytesType const* rightType); - void fromArray(Type const* leftType, ArrayType const* rightType); + void fromFixedBytesType(Type const* leftType, FixedBytesType const* rightType) const; + void fromArray(Type const* leftType, ArrayType const* rightType) const; void fromOptional(Type const* leftType, OptionalType const* rightType); - void fromSlice(Type const* leftType); + void fromSlice(Type const* leftType) const; void fromTuple(Type const* leftType, TupleType const* rightType); - void fromStringLiteral(Type const* leftType, StringLiteralType const* rightType); + void fromStringLiteral(Type const* leftType, StringLiteralType const* rightType) const; private: StackPusher& m_pusher; }; // end TypeConversion diff --git a/compiler/libsolidity/codegen/TVMTypeChecker.cpp b/compiler/libsolidity/codegen/TVMTypeChecker.cpp index 866db565..f72fb30a 100644 --- a/compiler/libsolidity/codegen/TVMTypeChecker.cpp +++ b/compiler/libsolidity/codegen/TVMTypeChecker.cpp @@ -362,7 +362,7 @@ void TVMTypeChecker::checkDeprecation(FunctionCall const& _functionCall) { m_errorReporter.warning(4767_error, _functionCall.location(), "\"tvm.functionId()\" is deprecated. Use: \"abi.functionId()\""); break; - case FunctionType::Kind::ABIBuildIntMsg: + case FunctionType::Kind::ABIEncodeIntMsg: if (kind == MagicType::Kind::TVM) m_errorReporter.warning(4063_error, _functionCall.location(), "\"tvm.buildIntMsg()\" is deprecated. Use: \"abi.encodeIntMsg()\""); @@ -445,12 +445,17 @@ bool TVMTypeChecker::visit(FunctionCall const& _functionCall) { auto functionType = to(expressionType); if (functionType->hasDeclaration()) { - auto fd = to(&functionType->declaration()); - if (fd && fd->name() == "onCodeUpgrade") { - if (m_inherHelper->isBaseFunction(fd)) { - m_errorReporter.typeError( - 7993_error, _functionCall.location(), - "It is forbidden to call base functions of \"onCodeUpgrade\"."); + if (auto fd = to(&functionType->declaration())) { + if (fd->name() == "onCodeUpgrade") { + if (m_inherHelper->isBaseFunction(fd)) { + m_errorReporter.typeError( + 7993_error, _functionCall.location(), + "It is forbidden to call base functions of \"onCodeUpgrade\"."); + } + } + if (fd->visibility() == Visibility::Getter) { + m_errorReporter.typeError(7162_error, _functionCall.location(), + "It is forbidden to call getter from the contract. Only off-chain."); } } } diff --git a/compiler/libsolidity/codegen/TvmAst.hpp b/compiler/libsolidity/codegen/TvmAst.hpp index 588d2b69..36c8cfb1 100644 --- a/compiler/libsolidity/codegen/TvmAst.hpp +++ b/compiler/libsolidity/codegen/TvmAst.hpp @@ -490,22 +490,24 @@ class Function : public TvmAstNode { class Contract : public TvmAstNode { public: - explicit Contract( + Contract( bool _isLib, bool _saveAllFunction, bool _upgradeFunc, bool upgradeOldSolidity, std::string _version, - std::vector> functions, - std::map _privateFunctions + std::vector> _functions, + std::map _privateFunctions, + std::map _getters ) : m_isLib{_isLib}, m_saveAllFunction{_saveAllFunction}, m_upgradeFunc{_upgradeFunc}, m_upgradeOldSolidity{upgradeOldSolidity}, m_version{std::move(_version)}, - m_functions{std::move(functions)}, - m_privateFunctions{std::move(_privateFunctions)} + m_functions{std::move(_functions)}, + m_privateFunctions{std::move(_privateFunctions)}, + m_getters{std::move(_getters)} { } void accept(TvmAstVisitor& _visitor) override; @@ -517,6 +519,7 @@ class Contract : public TvmAstNode { std::string const& version() const { return m_version; } std::vector> const& functions() const { return m_functions; } std::map const& privateFunctions() const { return m_privateFunctions; } + std::map const& getters() const { return m_getters; } private: bool m_isLib{}; bool m_saveAllFunction{}; @@ -525,6 +528,7 @@ class Contract : public TvmAstNode { std::string m_version; std::vector> m_functions; std::map m_privateFunctions; + std::map m_getters; }; Pointer gen(const std::string& cmd); diff --git a/compiler/libsolidity/codegen/TvmAstVisitor.cpp b/compiler/libsolidity/codegen/TvmAstVisitor.cpp index ef65dcc6..27f1bae1 100644 --- a/compiler/libsolidity/codegen/TvmAstVisitor.cpp +++ b/compiler/libsolidity/codegen/TvmAstVisitor.cpp @@ -703,6 +703,40 @@ bool Printer::visit(While &_node) { return false; } +void Printer::printTickTockAndGetters(bool _hasOnTickTock, std::map const& _getters) { + if (_hasOnTickTock || !_getters.empty()) { + tabs(); m_out << "JMPREF {" << std::endl; + { + ++m_tab; + + if (_hasOnTickTock) { + tabs(); m_out << "DUP" << std::endl; + tabs(); m_out << "EQINT -2" << std::endl; + tabs(); m_out << "IFJMPREF {" << std::endl; + tabs(); m_out << " .inline onTickTock" << std::endl; + tabs(); m_out << "}" << std::endl; + } + + if (!_getters.empty()) { + tabs(); m_out << "DICTPUSHCONST 19" << std::endl; + tabs(); m_out << "DICTUGETJMPZ" << std::endl; + tabs(); m_out << "THROW 11" << std::endl; + tabs(); m_out << ".code-dict-cell 19, {" << std::endl; + ++m_tab; + for (auto const& [id, name] : _getters) { + std::string slice = StrUtils::binaryStringToSlice(StrUtils::toBitString(id, 19, false).value()); + tabs(); m_out << "x" << slice << " = " << name << "," << std::endl; + } + --m_tab; + tabs(); m_out << "}" << std::endl; // end .code-dict-cell + } + + --m_tab; + } + tabs(); m_out << "}" << std::endl; // end JMPREF + } +} + bool Printer::visit(Contract &_node) { std::map privFuncs = _node.privateFunctions(); for (Pointer const& fun : _node.functions()) { @@ -724,12 +758,6 @@ bool Printer::visit(Contract &_node) { } if (!_node.isLib()) { - if (!hasOnTickTock) { - m_out << ".fragment onTickTock, {" << std::endl; - m_out << "}" << std::endl; - m_out << std::endl; - } - m_out << "; The code below forms a value of the StateInit type." << std::endl; m_out << ".blob x4_ ; split_depth = nothing" << std::endl; m_out << ".blob x4_ ; special = nothing" << std::endl; @@ -766,15 +794,11 @@ bool Printer::visit(Contract &_node) { tabs(); m_out << "IFJMPREF {" << std::endl; tabs(); m_out << " .inline main_external" << std::endl; tabs(); m_out << "}" << std::endl; - tabs(); m_out << "DUP" << std::endl; - tabs(); m_out << "EQINT -2" << std::endl; - tabs(); m_out << "IFJMPREF {" << std::endl; - tabs(); m_out << " .inline onTickTock" << std::endl; - tabs(); m_out << "}" << std::endl; - tabs(); m_out << "THROW 11" << std::endl; + printTickTockAndGetters(hasOnTickTock, _node.getters()); --m_tab; tabs(); m_out << "}" << std::endl; // end code }; + if (_node.upgradeOldSolidity() || _node.upgradeFunc()) { int func_id = _node.upgradeFunc() ? 1666 : 2; m_out << ".cell { ; wrapper for code" << std::endl; diff --git a/compiler/libsolidity/codegen/TvmAstVisitor.hpp b/compiler/libsolidity/codegen/TvmAstVisitor.hpp index 992d4672..aaecd4e4 100644 --- a/compiler/libsolidity/codegen/TvmAstVisitor.hpp +++ b/compiler/libsolidity/codegen/TvmAstVisitor.hpp @@ -89,6 +89,7 @@ class Printer : public TvmAstVisitor { void tabs(); void printPushInt(std::string const& arg, std::string const& comment = ""); void printPushInt(int i); + void printTickTockAndGetters(bool _hasOnTickTock, std::map const& _getters); private: std::ostream& m_out; int m_tab{}; diff --git a/compiler/libsolidity/parsing/Parser.cpp b/compiler/libsolidity/parsing/Parser.cpp index 068b49ae..1e15d868 100644 --- a/compiler/libsolidity/parsing/Parser.cpp +++ b/compiler/libsolidity/parsing/Parser.cpp @@ -480,6 +480,9 @@ Visibility Parser::parseVisibilitySpecifier() Token token = m_scanner->currentToken(); switch (token) { + case Token::Getter: + visibility = Visibility::Getter; + break; case Token::Public: visibility = Visibility::Public; break; diff --git a/compiler/libsolidity/parsing/Parser.h b/compiler/libsolidity/parsing/Parser.h index c4f982eb..7fb41d4b 100644 --- a/compiler/libsolidity/parsing/Parser.h +++ b/compiler/libsolidity/parsing/Parser.h @@ -81,6 +81,7 @@ class Parser: public langutil::ParserBase bool externalMsg = false; bool internalMsg = false; bool assembly = false; + bool isGetter = false; ASTPointer experimentalReturnExpression; }; diff --git a/compiler/scripts/install_deps.sh b/compiler/scripts/install_deps.sh index a07d5440..207b7203 100755 --- a/compiler/scripts/install_deps.sh +++ b/compiler/scripts/install_deps.sh @@ -71,47 +71,6 @@ case $(uname -s) in #------------------------------------------------------------------------------ Darwin) - case $(sw_vers -productVersion | awk -F . '{print $1"."$2}') in - 10.9) - echo "Installing solidity dependencies on OS X 10.9 Mavericks." - ;; - 10.10) - echo "Installing solidity dependencies on OS X 10.10 Yosemite." - ;; - 10.11) - echo "Installing solidity dependencies on OS X 10.11 El Capitan." - ;; - 10.12) - echo "Installing solidity dependencies on macOS 10.12 Sierra." - ;; - 10.13) - echo "Installing solidity dependencies on macOS 10.13 High Sierra." - ;; - 10.14) - echo "Installing solidity dependencies on macOS 10.14 Mojave." - ;; - 10.15) - echo "Installing solidity dependencies on macOS 10.15 Catalina." - ;; - 11.0 | 11.1 | 11.2 | 11.3 | 11.4) - echo "Installing solidity dependencies on macOS 11.0 / 11.1 / 11.2 / 11.3 / 11.4 Big Sur." - ;; - 12.*) - echo "Installing solidity dependencies on macOS 12 Monterey." - ;; - 13.*) - echo "Installing solidity dependencies on macOS 13." - ;; - 14.*) - echo "Installing solidity dependencies on macOS 14." - ;; - *) - echo "Unsupported macOS version." - echo "We only support Mavericks, Yosemite, El Capitan, Sierra, High Sierra, Mojave, Catalina, Big Sur and Monterey." - exit 1 - ;; - esac - # Check for Homebrew install and abort if it is not installed. brew -v > /dev/null 2>&1 || { echo >&2 "ERROR - solidity requires a Homebrew install. See https://brew.sh."; exit 1; } brew update diff --git a/compiler/solc/CommandLineInterface.cpp b/compiler/solc/CommandLineInterface.cpp index abcb87a6..7897678d 100644 --- a/compiler/solc/CommandLineInterface.cpp +++ b/compiler/solc/CommandLineInterface.cpp @@ -465,7 +465,6 @@ void CommandLineInterface::compile() SourceReferenceFormatter formatter(serr(false), *m_compiler, coloredOutput(m_options), m_options.formatting.withErrorIds); - bool successful = true; try { if (m_options.metadata.literalSources) @@ -547,6 +546,7 @@ void CommandLineInterface::compile() m_compiler->setOutputFolder(m_options.output.dir.string()); m_compiler->setTVMVersion(m_options.tvmParams.tvmVersion); + bool successful = true; bool didCompileSomething = false; std::tie(successful, didCompileSomething) = m_compiler->compile(); m_hasOutput |= didCompileSomething; @@ -557,6 +557,8 @@ void CommandLineInterface::compile() formatter.printErrorInformation(*error); } + if (!successful) + solThrow(CommandLineExecutionError, ""); } catch (CompilerError const& _exception) { @@ -581,22 +583,6 @@ void CommandLineInterface::compile() solThrow(CommandLineExecutionError, ""); } } - catch (util::Exception const& exception) - { - - serr() << exception.what() << std::endl; - serr() << exception.lineInfo() << std::endl; - serr() << "Internal error" << std::endl - << "Please report your bug to https://github.com/everx-labs/TVM-Solidity-Compiler/issues" << std::endl; - } - catch (...) - { - serr() << "Internal error" << std::endl - << "Please report your bug to https://github.com/everx-labs/TVM-Solidity-Compiler/issues" << std::endl; - } - - if (!successful) - solThrow(CommandLineExecutionError, ""); } void CommandLineInterface::handleAst() diff --git a/compiler/solc/main.cpp b/compiler/solc/main.cpp index 4237f9ac..2aa901fc 100644 --- a/compiler/solc/main.cpp +++ b/compiler/solc/main.cpp @@ -31,6 +31,11 @@ using namespace solidity; +namespace { +void printReportBug() { + std::cerr << "Please report your bug to https://github.com/everx-labs/TVM-Solidity-Compiler/issues" << std::endl; +} +} int main(int argc, char** argv) { @@ -43,24 +48,28 @@ int main(int argc, char** argv) { std::cerr << "SMT logic error:" << std::endl; std::cerr << boost::diagnostic_information(_exception); + printReportBug(); return 2; } catch (langutil::UnimplementedFeatureError const& _exception) { std::cerr << "Unimplemented feature:" << std::endl; std::cerr << boost::diagnostic_information(_exception); + printReportBug(); return 2; } catch (langutil::InternalCompilerError const& _exception) { std::cerr << "Internal compiler error:" << std::endl; std::cerr << boost::diagnostic_information(_exception); + printReportBug(); return 2; } catch (...) { std::cerr << "Uncaught exception:" << std::endl; std::cerr << boost::current_exception_diagnostic_information() << std::endl; + printReportBug(); return 2; } } diff --git a/lib/stdlib.sol b/lib/stdlib.sol index 2711cbbb..a6ebbedd 100644 --- a/lib/stdlib.sol +++ b/lib/stdlib.sol @@ -118,6 +118,24 @@ contract stdlib { return st; } + // Append slice in hex format with tag _ if needs + function __appendSliceDataAsHex(stack(TvmBuilder) st, TvmSlice data) pure private returns(stack(TvmBuilder)) { + while (data.bits() >= 4) { + uint9 bits = uint9(math.min(data.bits() / 4 * 4, 256)); + uint value = data.loadUint(bits); + st = __convertIntToHexString(st, value, bits / 4, true, true); + } + if (data.bits() != 0) { + uint10 shift = 4 - data.bits(); + int value = data.loadUint(uint9(data.bits())); + value = (value << 1) + 1; + value <<= (shift - 1); + st = __convertIntToHexString(st, value, 1, true, true); + st = __appendBytes1(st, bytes1("_")); + } + return st; + } + function __appendSliceToStringBuilder(stack(TvmBuilder) st, TvmSlice s) pure private returns(stack(TvmBuilder)) { uint10 restBits = st.top().remBits() - 7; // 1023 - 7 = 1016 = 127 * 8 TvmSlice ss = s.loadSlice(math.min(restBits, s.bits()), 0); @@ -210,15 +228,35 @@ contract stdlib { return st; } - function __convertAddressToHexString(stack(TvmBuilder) st, address addr) private pure returns (stack(TvmBuilder)) { - (int32 wid, uint value) = addr.unpack(); - st = __convertIntToHexString(st, wid, 0, false, true); - uint16 remBits = st.top().remBits(); - if (remBits < 8) { - st.push(TvmBuilder()); + function __appendAnyCast(stack(TvmBuilder) st, TvmSlice addr) private pure returns (stack(TvmBuilder), TvmSlice) { + bool hasAnycast = addr.load(bool); + if (hasAnycast) { + uint5 depth = addr.load(uint5); + st = __appendSliceDataAsHex(st, addr.loadSlice(depth)); + st = __appendBytes1(st, bytes1(":")); + } + return (st, addr); + } + + function __convertAddressToHexString(stack(TvmBuilder) st, TvmSlice addr) private pure returns (stack(TvmBuilder)) { + uint2 addrType = addr.load(uint2); + if (addrType == 2) { // addr_std + (st, addr) = __appendAnyCast(st, addr); + st = __convertIntToString(st, addr.load(int8), 0, false); + st = __appendBytes1(st, bytes1(":")); + st = __convertIntToHexString(st, addr.load(uint256), 64, true, true); + } else if (addrType == 1) { // addr_extern + st = __appendBytes1(st, bytes1(":")); + addr.load(uint9); + st = __appendSliceDataAsHex(st, addr); + } else if (addrType == 3) { // addr_var + (st, addr) = __appendAnyCast(st, addr); + addr.skip(9); // addr_len + st = __convertIntToString(st, addr.load(int32), 0, false); + st = __appendBytes1(st, bytes1(":")); + st = __appendSliceDataAsHex(st, addr); } - st.top().store(bytes1(":")); - return __convertIntToHexString(st, value, 64, true, true); + return st; } function __convertFixedPointToString(stack(TvmBuilder) st, int257 value, uint16 fractionalDigits, uint fractionPow10) private pure returns (stack(TvmBuilder)) { diff --git a/lib/stdlib_sol.tvm b/lib/stdlib_sol.tvm index 48f004bd..a24d00b4 100644 --- a/lib/stdlib_sol.tvm +++ b/lib/stdlib_sol.tvm @@ -23,327 +23,6 @@ .loc stdlib.sol, 0 } -.fragment __appendBytes1NTimes, { - .loc stdlib.sol, 115 - PUSHCONT { - .loc stdlib.sol, 116 - DUP2 - CALLREF { - .inline __appendBytes1 - } - POP S2 - .loc stdlib.sol, 0 - } - REPEAT - .loc stdlib.sol, 118 - DROP - .loc stdlib.sol, 0 -} - -.fragment __appendSliceToStringBuilder, { - .loc stdlib.sol, 122 - OVER - FIRST - BREMBITS - ADDCONST -7 - .loc stdlib.sol, 123 - PUXCPU S1, S-1, S0 - SBITS - MIN - LDSLICEX - POP S2 - .loc stdlib.sol, 124 - PUSH S2 - UNPAIR - ROTREV - STSLICE - SWAP - PAIR - POP S2 - .loc stdlib.sol, 125 - DUP - SEMPTY - PUSHCONT { - .loc stdlib.sol, 127 - DUP - NEWC - STSLICE - .loc stdlib.sol, 128 - PUSH S2 - PAIR - POP S2 - .loc stdlib.sol, 0 - } - IFNOT - .loc stdlib.sol, 130 - DROP - .loc stdlib.sol, 0 -} - -.fragment __appendStringToStringBuilderWithNoShift, { - .loc stdlib.sol, 134 - DUP - CTOS - .loc stdlib.sol, 135 - PUSHCONT { - .loc stdlib.sol, 136 - PUSH S2 - UNPAIR - XCPU2 S1, S2, S2 - SBITS - LDSLICEX - POP S4 - STSLICER - SWAP - PAIR - POP S3 - .loc stdlib.sol, 137 - DUP - SEMPTY - IFRETALT - .loc stdlib.sol, 139 - NEWC - PUSH S3 - PAIR - POP S3 - .loc stdlib.sol, 140 - LDREFRTOS - NIP - .loc stdlib.sol, 0 - } - AGAINBRK - .loc stdlib.sol, 142 - DROP2 - .loc stdlib.sol, 0 -} - -.fragment __appendStringToStringBuilder, { - .loc stdlib.sol, 146 - NULL - .loc stdlib.sol, 147 - PUSH S2 - FIRST - BBITS - PUSHCONT { - .loc stdlib.sol, 148 - ROTREV - CALLREF { - .inline __appendStringToStringBuilderWithNoShift - } - NIP - .loc stdlib.sol, 0 - } - IFNOTJMP - .loc stdlib.sol, 150 - OVER - CTOS - .loc stdlib.sol, 151 - PUSHCONT { - .loc stdlib.sol, 152 - BLKPUSH 2, 0 - SBITS - LDSLICEX - POP S2 - PUXC S4, S-1 - .loc stdlib.sol, 153 - CALLREF { - .inline __appendSliceToStringBuilder - } - POP S4 - .loc stdlib.sol, 154 - DUP - SEMPTY - IFRETALT - .loc stdlib.sol, 156 - LDREFRTOS - NIP - .loc stdlib.sol, 0 - } - AGAINBRK - .loc stdlib.sol, 158 - BLKDROP 3 - .loc stdlib.sol, 0 -} - -.fragment __createStringBuilder, { - .loc stdlib.sol, 90 - NEWC - NULL - PAIR - .loc stdlib.sol, 0 -} - -.fragment __makeString, { - .loc stdlib.sol, 96 - UNPAIR - SWAP - .loc stdlib.sol, 97 - PUSHCONT { - OVER - ISNULL - NOT - } - PUSHCONT { - .loc stdlib.sol, 98 - OVER - UNPAIR - POP S3 - .loc stdlib.sol, 99 - STBREF - .loc stdlib.sol, 0 - } - WHILE - .loc stdlib.sol, 102 - ENDC - NIP - .loc stdlib.sol, 0 -} - -.fragment __subCell, { - .loc stdlib.sol, 353 - PUSH S2 - PUSHINT 127 - DIVMOD - .loc stdlib.sol, 354 - OVER - NEQINT 0 - OVER - EQINT 0 - AND - PUSHCONT { - .loc stdlib.sol, 355 - DROP - DEC - .loc stdlib.sol, 356 - PUSHINT 127 - .loc stdlib.sol, 0 - } - IF - .loc stdlib.sol, 359 - PUSH S5 - CTOS - .loc stdlib.sol, 360 - PUSH S2 - PUSHCONT { - .loc stdlib.sol, 361 - DUP - SREFS - EQINT 1 - THROWIFNOT 70 - .loc stdlib.sol, 362 - LDREFRTOS - NIP - .loc stdlib.sol, 0 - } - REPEAT - .loc stdlib.sol, 365 - OVER - MULCONST 8 - POP S2 - .loc stdlib.sol, 366 - DUP - SBITS - PUSH S2 - GEQ - THROWIFNOT 70 - .loc stdlib.sol, 367 - OVER - SDSKIPFIRST - .loc stdlib.sol, 369 - PUSH S4 - MULCONST 8 - POP S5 - .loc stdlib.sol, 370 - CALLREF { - .inline __createStringBuilder - } - .loc stdlib.sol, 371 - PUSHCONT { - .loc stdlib.sol, 372 - OVER - SBITS - PUSH S6 - MIN - UFITS 10 - .loc stdlib.sol, 373 - PUSH2 S6, S0 - SUB - POP S7 - PUXC S2, S-1 - .loc stdlib.sol, 374 - LDSLICEX - POP S3 - .loc stdlib.sol, 375 - CALLREF { - .inline __appendSliceToStringBuilder - } - .loc stdlib.sol, 376 - PUSH S5 - EQINT 0 - PUSH S2 - SEMPTY - OR - IFRETALT - .loc stdlib.sol, 379 - OVER - LDREFRTOS - NIP - POP S2 - .loc stdlib.sol, 0 - } - AGAINBRK - .loc stdlib.sol, 381 - BLKSWAP 2, 4 - SWAP - EQINT 0 - OR - THROWIFNOT 70 - .loc stdlib.sol, 382 - CALLREF { - .inline __makeString - } - BLKDROP2 5, 1 - .loc stdlib.sol, 0 -} - -.fragment __arraySlice, { - .loc stdlib.sol, 347 - DUP2 - LEQ - THROWIFNOT 70 - .loc stdlib.sol, 348 - OVER - SUB - .loc stdlib.sol, 349 - FALSE - CALLREF { - .inline __subCell - } - .loc stdlib.sol, 0 -} - -.fragment __concatenateStrings, { - .loc stdlib.sol, 411 - CALLREF { - .inline __createStringBuilder - } - .loc stdlib.sol, 412 - ROT - CALLREF { - .inline __appendStringToStringBuilderWithNoShift - } - .loc stdlib.sol, 413 - SWAP - CALLREF { - .inline __appendStringToStringBuilder - } - .loc stdlib.sol, 414 - CALLREF { - .inline __makeString - } - .loc stdlib.sol, 0 -} - .fragment __parseInteger, { .loc stdlib.sol, 73 OVER @@ -386,35 +65,35 @@ } .fragment __convertIntToHexString, { - .loc stdlib.sol, 243 + .loc stdlib.sol, 281 PUSH S3 LESSINT 0 - .loc stdlib.sol, 244 + .loc stdlib.sol, 282 ROLL 4 ABS - .loc stdlib.sol, 245 + .loc stdlib.sol, 283 PUSH S5 FIRST BREMBITS RSHIFT 3 - .loc stdlib.sol, 247 + .loc stdlib.sol, 285 ROT PUSHCONT { - .loc stdlib.sol, 248 + .loc stdlib.sol, 286 DUP PUSHCONT { - .loc stdlib.sol, 249 + .loc stdlib.sol, 287 NEWC PUSH S6 PAIR POP S6 - .loc stdlib.sol, 250 + .loc stdlib.sol, 288 DROP PUSHINT 127 .loc stdlib.sol, 0 } IFNOT - .loc stdlib.sol, 252 + .loc stdlib.sol, 290 PUSH S5 UNPAIR PUSHINT 45 @@ -423,34 +102,34 @@ SWAP PAIR POP S6 - .loc stdlib.sol, 253 + .loc stdlib.sol, 291 DEC .loc stdlib.sol, 0 } IF - .loc stdlib.sol, 256 + .loc stdlib.sol, 294 SWAP PUSHINT 16 CALLREF { .inline __parseInteger } - .loc stdlib.sol, 258 + .loc stdlib.sol, 296 PUSH2 S5, S0 GREATER PUSHCONT { - .loc stdlib.sol, 259 + .loc stdlib.sol, 297 PUSH S4 PUSHINT 48 PUSHINT 32 CONDSEL - .loc stdlib.sol, 260 + .loc stdlib.sol, 298 PUSH2 S6, S1 SUB - .loc stdlib.sol, 261 + .loc stdlib.sol, 299 PUSH2 S0, S4 MIN PUSHCONT { - .loc stdlib.sol, 262 + .loc stdlib.sol, 300 PUSH S8 UNPAIR PUXC S3, S1 @@ -461,20 +140,20 @@ .loc stdlib.sol, 0 } REPEAT - .loc stdlib.sol, 264 + .loc stdlib.sol, 302 PUSH2 S0, S4 GREATER PUSHCONT { - .loc stdlib.sol, 265 + .loc stdlib.sol, 303 NEWC PUSH S9 PAIR POP S9 - .loc stdlib.sol, 266 + .loc stdlib.sol, 304 PUSH2 S0, S4 SUB PUSHCONT { - .loc stdlib.sol, 267 + .loc stdlib.sol, 305 PUSH S8 UNPAIR PUXC S3, S1 @@ -485,12 +164,12 @@ .loc stdlib.sol, 0 } REPEAT - .loc stdlib.sol, 269 + .loc stdlib.sol, 307 PUSH S4 ADDCONST 127 } PUSHCONT { - .loc stdlib.sol, 271 + .loc stdlib.sol, 309 PUSH S4 } IFELSE @@ -501,23 +180,23 @@ DROP2 } IF - .loc stdlib.sol, 275 + .loc stdlib.sol, 313 ROLL 3 PUSHINT 97 PUSHINT 65 CONDSEL ADDCONST -10 - .loc stdlib.sol, 276 + .loc stdlib.sol, 314 PUSH2 S1, S3 MIN PUSHCONT { - .loc stdlib.sol, 278 + .loc stdlib.sol, 316 PUSH2 S2, S2 ISNULL THROWIF 63 UNPAIR POP S4 - .loc stdlib.sol, 279 + .loc stdlib.sol, 317 PUSH S7 UNPAIR XCPU S2, S0 @@ -533,26 +212,26 @@ .loc stdlib.sol, 0 } REPEAT - .loc stdlib.sol, 281 + .loc stdlib.sol, 319 PUSH2 S1, S3 GREATER PUSHCONT { - .loc stdlib.sol, 282 + .loc stdlib.sol, 320 NEWC PUSH S7 PAIR POP S7 - .loc stdlib.sol, 283 + .loc stdlib.sol, 321 PUSH2 S1, S3 SUB PUSHCONT { - .loc stdlib.sol, 285 + .loc stdlib.sol, 323 PUSH2 S2, S2 ISNULL THROWIF 63 UNPAIR POP S4 - .loc stdlib.sol, 286 + .loc stdlib.sol, 324 PUSH S7 UNPAIR XCPU S2, S0 @@ -570,109 +249,466 @@ REPEAT .loc stdlib.sol, 0 } - IF - .loc stdlib.sol, 289 - BLKDROP 6 - .loc stdlib.sol, 0 -} - -.fragment __convertAddressToHexString, { - .loc stdlib.sol, 214 - REWRITESTDADDR - .loc stdlib.sol, 215 - PUXC S2, S1 - PUSHINT 0 + IF + .loc stdlib.sol, 327 + BLKDROP 6 + .loc stdlib.sol, 0 +} + +.fragment __appendSliceDataAsHex, { + .loc stdlib.sol, 123 + PUSHCONT { + DUP + SBITS + GTINT 3 + } + PUSHCONT { + .loc stdlib.sol, 124 + DUP + SBITS + RSHIFT 2 + MULCONST 4 + PUSHPOW2 8 + MIN + UFITS 9 + .loc stdlib.sol, 125 + DUP2 + LDUX + POP S3 + PUXC2 S3, S-1, S0 + .loc stdlib.sol, 126 + RSHIFT 2 + TRUE + DUP + CALLREF { + .inline __convertIntToHexString + } + POP S2 + .loc stdlib.sol, 0 + } + WHILE + .loc stdlib.sol, 128 + DUP + SBITS + PUSHCONT { + .loc stdlib.sol, 129 + PUSHINT 4 + OVER + SBITS + SUB + .loc stdlib.sol, 130 + PUSH2 S1, S1 + SBITS + UFITS 9 + LDUX + POP S3 + .loc stdlib.sol, 131 + LSHIFT 1 + INC + .loc stdlib.sol, 132 + SWAP + DEC + LSHIFT + .loc stdlib.sol, 133 + PUXC S2, S-1 + PUSHINT 1 + TRUE + DUP + CALLREF { + .inline __convertIntToHexString + } + .loc stdlib.sol, 134 + PUSHINT 95 + CALLREF { + .inline __appendBytes1 + } + POP S2 + .loc stdlib.sol, 0 + } + IF + .loc stdlib.sol, 136 + DROP + .loc stdlib.sol, 0 +} + +.fragment __appendAnyCast, { + .loc stdlib.sol, 232 + LDI 1 + SWAP + .loc stdlib.sol, 233 + PUSHCONT { + .loc stdlib.sol, 234 + LDU 5 + PU2XC S2, S-1, S1 + .loc stdlib.sol, 235 + LDSLICEX + POP S3 + CALLREF { + .inline __appendSliceDataAsHex + } + .loc stdlib.sol, 236 + PUSHINT 58 + CALLREF { + .inline __appendBytes1 + } + POP S2 + .loc stdlib.sol, 0 + } + IF + .loc stdlib.sol, 0 +} + +.fragment __appendBytes1NTimes, { + .loc stdlib.sol, 115 + PUSHCONT { + .loc stdlib.sol, 116 + DUP2 + CALLREF { + .inline __appendBytes1 + } + POP S2 + .loc stdlib.sol, 0 + } + REPEAT + .loc stdlib.sol, 118 + DROP + .loc stdlib.sol, 0 +} + +.fragment __appendSliceToStringBuilder, { + .loc stdlib.sol, 140 + OVER + FIRST + BREMBITS + ADDCONST -7 + .loc stdlib.sol, 141 + PUXCPU S1, S-1, S0 + SBITS + MIN + LDSLICEX + POP S2 + .loc stdlib.sol, 142 + PUSH S2 + UNPAIR + ROTREV + STSLICE + SWAP + PAIR + POP S2 + .loc stdlib.sol, 143 + DUP + SEMPTY + PUSHCONT { + .loc stdlib.sol, 145 + DUP + NEWC + STSLICE + .loc stdlib.sol, 146 + PUSH S2 + PAIR + POP S2 + .loc stdlib.sol, 0 + } + IFNOT + .loc stdlib.sol, 148 + DROP + .loc stdlib.sol, 0 +} + +.fragment __appendStringToStringBuilderWithNoShift, { + .loc stdlib.sol, 152 + DUP + CTOS + .loc stdlib.sol, 153 + PUSHCONT { + .loc stdlib.sol, 154 + PUSH S2 + UNPAIR + XCPU2 S1, S2, S2 + SBITS + LDSLICEX + POP S4 + STSLICER + SWAP + PAIR + POP S3 + .loc stdlib.sol, 155 + DUP + SEMPTY + IFRETALT + .loc stdlib.sol, 157 + NEWC + PUSH S3 + PAIR + POP S3 + .loc stdlib.sol, 158 + LDREFRTOS + NIP + .loc stdlib.sol, 0 + } + AGAINBRK + .loc stdlib.sol, 160 + DROP2 + .loc stdlib.sol, 0 +} + +.fragment __appendStringToStringBuilder, { + .loc stdlib.sol, 164 + NULL + .loc stdlib.sol, 165 + PUSH S2 + FIRST + BBITS + PUSHCONT { + .loc stdlib.sol, 166 + ROTREV + CALLREF { + .inline __appendStringToStringBuilderWithNoShift + } + NIP + .loc stdlib.sol, 0 + } + IFNOTJMP + .loc stdlib.sol, 168 + OVER + CTOS + .loc stdlib.sol, 169 + PUSHCONT { + .loc stdlib.sol, 170 + BLKPUSH 2, 0 + SBITS + LDSLICEX + POP S2 + PUXC S4, S-1 + .loc stdlib.sol, 171 + CALLREF { + .inline __appendSliceToStringBuilder + } + POP S4 + .loc stdlib.sol, 172 + DUP + SEMPTY + IFRETALT + .loc stdlib.sol, 174 + LDREFRTOS + NIP + .loc stdlib.sol, 0 + } + AGAINBRK + .loc stdlib.sol, 176 + BLKDROP 3 + .loc stdlib.sol, 0 +} + +.fragment __createStringBuilder, { + .loc stdlib.sol, 90 + NEWC + NULL + PAIR + .loc stdlib.sol, 0 +} + +.fragment __makeString, { + .loc stdlib.sol, 96 + UNPAIR + SWAP + .loc stdlib.sol, 97 + PUSHCONT { + OVER + ISNULL + NOT + } + PUSHCONT { + .loc stdlib.sol, 98 + OVER + UNPAIR + POP S3 + .loc stdlib.sol, 99 + STBREF + .loc stdlib.sol, 0 + } + WHILE + .loc stdlib.sol, 102 + ENDC + NIP + .loc stdlib.sol, 0 +} + +.fragment __subCell, { + .loc stdlib.sol, 391 + PUSH S2 + PUSHINT 127 + DIVMOD + .loc stdlib.sol, 392 + OVER + NEQINT 0 + OVER + EQINT 0 + AND + PUSHCONT { + .loc stdlib.sol, 393 + DROP + DEC + .loc stdlib.sol, 394 + PUSHINT 127 + .loc stdlib.sol, 0 + } + IF + .loc stdlib.sol, 397 + PUSH S5 + CTOS + .loc stdlib.sol, 398 + PUSH S2 + PUSHCONT { + .loc stdlib.sol, 399 + DUP + SREFS + EQINT 1 + THROWIFNOT 70 + .loc stdlib.sol, 400 + LDREFRTOS + NIP + .loc stdlib.sol, 0 + } + REPEAT + .loc stdlib.sol, 403 + OVER + MULCONST 8 + POP S2 + .loc stdlib.sol, 404 DUP - TRUE + SBITS + PUSH S2 + GEQ + THROWIFNOT 70 + .loc stdlib.sol, 405 + OVER + SDSKIPFIRST + .loc stdlib.sol, 407 + PUSH S4 + MULCONST 8 + POP S5 + .loc stdlib.sol, 408 CALLREF { - .inline __convertIntToHexString + .inline __createStringBuilder } - POP S2 - .loc stdlib.sol, 216 - OVER - FIRST - BREMBITS - .loc stdlib.sol, 217 - LESSINT 8 + .loc stdlib.sol, 409 PUSHCONT { - .loc stdlib.sol, 218 - NEWC + .loc stdlib.sol, 410 + OVER + SBITS + PUSH S6 + MIN + UFITS 10 + .loc stdlib.sol, 411 + PUSH2 S6, S0 + SUB + POP S7 + PUXC S2, S-1 + .loc stdlib.sol, 412 + LDSLICEX + POP S3 + .loc stdlib.sol, 413 + CALLREF { + .inline __appendSliceToStringBuilder + } + .loc stdlib.sol, 414 + PUSH S5 + EQINT 0 PUSH S2 - PAIR + SEMPTY + OR + IFRETALT + .loc stdlib.sol, 417 + OVER + LDREFRTOS + NIP POP S2 .loc stdlib.sol, 0 } - IF - .loc stdlib.sol, 220 - OVER - UNPAIR - PUSHINT 58 - ROT - STU 8 + AGAINBRK + .loc stdlib.sol, 419 + BLKSWAP 2, 4 SWAP - PAIR - POP S2 - .loc stdlib.sol, 221 - PUSHINT 64 - TRUE - DUP + EQINT 0 + OR + THROWIFNOT 70 + .loc stdlib.sol, 420 CALLREF { - .inline __convertIntToHexString + .inline __makeString } + BLKDROP2 5, 1 .loc stdlib.sol, 0 } -.fragment __convertBoolToStringBuilder, { - .loc stdlib.sol, 293 - PUSHCONT { - PUSHREF { - .blob x74727565 - } - CTOS +.fragment __arraySlice, { + .loc stdlib.sol, 385 + DUP2 + LEQ + THROWIFNOT 70 + .loc stdlib.sol, 386 + OVER + SUB + .loc stdlib.sol, 387 + FALSE + CALLREF { + .inline __subCell } - PUSHCONT { - PUSHREF { - .blob x66616c7365 - } - CTOS + .loc stdlib.sol, 0 +} + +.fragment __concatenateStrings, { + .loc stdlib.sol, 449 + CALLREF { + .inline __createStringBuilder } - IFELSE + .loc stdlib.sol, 450 + ROT CALLREF { - .inline __appendSliceToStringBuilder + .inline __appendStringToStringBuilderWithNoShift + } + .loc stdlib.sol, 451 + SWAP + CALLREF { + .inline __appendStringToStringBuilder + } + .loc stdlib.sol, 452 + CALLREF { + .inline __makeString } .loc stdlib.sol, 0 } .fragment __convertIntToString, { - .loc stdlib.sol, 164 + .loc stdlib.sol, 182 PUSH S2 LESSINT 0 - .loc stdlib.sol, 165 + .loc stdlib.sol, 183 ROLL 3 ABS - .loc stdlib.sol, 166 + .loc stdlib.sol, 184 PUSH S4 FIRST BREMBITS RSHIFT 3 - .loc stdlib.sol, 168 + .loc stdlib.sol, 186 ROT PUSHCONT { - .loc stdlib.sol, 169 + .loc stdlib.sol, 187 DUP PUSHCONT { - .loc stdlib.sol, 170 + .loc stdlib.sol, 188 NEWC PUSH S5 PAIR POP S5 - .loc stdlib.sol, 171 + .loc stdlib.sol, 189 DROP PUSHINT 127 .loc stdlib.sol, 0 } IFNOT - .loc stdlib.sol, 173 + .loc stdlib.sol, 191 PUSH S4 UNPAIR PUSHINT 45 @@ -681,34 +717,34 @@ SWAP PAIR POP S5 - .loc stdlib.sol, 174 + .loc stdlib.sol, 192 DEC .loc stdlib.sol, 0 } IF - .loc stdlib.sol, 177 + .loc stdlib.sol, 195 SWAP PUSHINT 10 CALLREF { .inline __parseInteger } - .loc stdlib.sol, 179 + .loc stdlib.sol, 197 PUSH2 S4, S0 GREATER PUSHCONT { - .loc stdlib.sol, 180 + .loc stdlib.sol, 198 PUSH S3 PUSHINT 48 PUSHINT 32 CONDSEL - .loc stdlib.sol, 181 + .loc stdlib.sol, 199 PUSH2 S5, S1 SUB - .loc stdlib.sol, 182 + .loc stdlib.sol, 200 PUSH2 S0, S4 MIN PUSHCONT { - .loc stdlib.sol, 183 + .loc stdlib.sol, 201 PUSH S7 UNPAIR PUXC S3, S1 @@ -719,20 +755,20 @@ .loc stdlib.sol, 0 } REPEAT - .loc stdlib.sol, 185 + .loc stdlib.sol, 203 PUSH2 S0, S4 GREATER PUSHCONT { - .loc stdlib.sol, 186 + .loc stdlib.sol, 204 NEWC PUSH S8 PAIR POP S8 - .loc stdlib.sol, 187 + .loc stdlib.sol, 205 PUSH2 S0, S4 SUB PUSHCONT { - .loc stdlib.sol, 188 + .loc stdlib.sol, 206 PUSH S7 UNPAIR PUXC S3, S1 @@ -743,12 +779,12 @@ .loc stdlib.sol, 0 } REPEAT - .loc stdlib.sol, 190 + .loc stdlib.sol, 208 PUSH S4 ADDCONST 127 } PUSHCONT { - .loc stdlib.sol, 192 + .loc stdlib.sol, 210 PUSH S4 } IFELSE @@ -759,15 +795,15 @@ DROP2 } IF - .loc stdlib.sol, 196 + .loc stdlib.sol, 214 PUSH2 S0, S2 MIN PUSHCONT { - .loc stdlib.sol, 198 + .loc stdlib.sol, 216 OVER UNPAIR POP S3 - .loc stdlib.sol, 199 + .loc stdlib.sol, 217 PUSH S6 UNPAIR XCHG S2 @@ -779,24 +815,24 @@ .loc stdlib.sol, 0 } REPEAT - .loc stdlib.sol, 201 + .loc stdlib.sol, 219 PUSH2 S0, S2 GREATER PUSHCONT { - .loc stdlib.sol, 202 + .loc stdlib.sol, 220 NEWC PUSH S6 PAIR POP S6 PUSH2 S0, S2 - .loc stdlib.sol, 203 + .loc stdlib.sol, 221 SUB PUSHCONT { - .loc stdlib.sol, 205 + .loc stdlib.sol, 223 OVER UNPAIR POP S3 - .loc stdlib.sol, 206 + .loc stdlib.sol, 224 PUSH S6 UNPAIR XCHG S2 @@ -811,23 +847,150 @@ .loc stdlib.sol, 0 } IF - .loc stdlib.sol, 210 + .loc stdlib.sol, 228 BLKDROP 5 .loc stdlib.sol, 0 } +.fragment __convertAddressToHexString, { + .loc stdlib.sol, 242 + LDU 2 + XCPU S1, S0 + .loc stdlib.sol, 243 + EQINT 2 + PUSHCONT { + .loc stdlib.sol, 244 + BLKPUSH 2, 2 + CALLREF { + .inline __appendAnyCast + } + .loc stdlib.sol, 245 + LDI 8 + POP S4 + PUSHINT 0 + DUP + CALLREF { + .inline __convertIntToString + } + .loc stdlib.sol, 246 + PUSHINT 58 + CALLREF { + .inline __appendBytes1 + } + .loc stdlib.sol, 247 + PUSH S2 + LDU 256 + POP S4 + PUSHINT 64 + TRUE + DUP + CALLREF { + .inline __convertIntToHexString + } + POP S3 + } + PUSHCONT { + DUP + EQINT 1 + PUSHCONT { + .loc stdlib.sol, 249 + PUSH S2 + PUSHINT 58 + CALLREF { + .inline __appendBytes1 + } + POP S3 + .loc stdlib.sol, 250 + OVER + LDU 9 + XCPU2 S3, S4, S3 + BLKDROP2 2, 2 + .loc stdlib.sol, 251 + CALLREF { + .inline __appendSliceDataAsHex + } + POP S3 + } + PUSHCONT { + DUP + EQINT 3 + PUSHCONT { + .loc stdlib.sol, 253 + BLKPUSH 2, 2 + CALLREF { + .inline __appendAnyCast + } + SWAP + POP S4 + .loc stdlib.sol, 254 + PUSHINT 9 + SDSKIPFIRST + POP S2 + BLKPUSH 2, 2 + .loc stdlib.sol, 255 + LDI 32 + POP S4 + PUSHINT 0 + DUP + CALLREF { + .inline __convertIntToString + } + .loc stdlib.sol, 256 + PUSHINT 58 + CALLREF { + .inline __appendBytes1 + } + .loc stdlib.sol, 257 + PUSH S2 + CALLREF { + .inline __appendSliceDataAsHex + } + POP S3 + .loc stdlib.sol, 0 + } + IF + } + IFELSE + } + IFELSE + .loc stdlib.sol, 259 + DROP2 + .loc stdlib.sol, 0 +} + +.fragment __convertBoolToStringBuilder, { + .loc stdlib.sol, 331 + PUSHCONT { + PUSHREF { + .blob x74727565 + } + CTOS + } + PUSHCONT { + PUSHREF { + .blob x66616c7365 + } + CTOS + } + IFELSE + CALLREF { + .inline __appendSliceToStringBuilder + } + .loc stdlib.sol, 0 +} + .fragment __convertFixedPointToString, { - .loc stdlib.sol, 225 + .loc stdlib.sol, 263 PUSH S2 LESSINT 0 PUSHCONT { - .loc stdlib.sol, 226 + .loc stdlib.sol, 264 PUSH S3 FIRST BREMBITS LESSINT 8 PUSHCONT { - .loc stdlib.sol, 227 + .loc stdlib.sol, 265 NEWC PUSH S4 PAIR @@ -835,7 +998,7 @@ .loc stdlib.sol, 0 } IF - .loc stdlib.sol, 229 + .loc stdlib.sol, 267 PUSH S3 UNPAIR PUSHINT 45 @@ -847,12 +1010,12 @@ .loc stdlib.sol, 0 } IF - .loc stdlib.sol, 231 + .loc stdlib.sol, 269 ROT ABS SWAP DIVMOD - .loc stdlib.sol, 232 + .loc stdlib.sol, 270 PUXC S3, S1 PUSHINT 0 DUP @@ -860,13 +1023,13 @@ .inline __convertIntToString } POP S3 - .loc stdlib.sol, 233 + .loc stdlib.sol, 271 PUSH S2 FIRST BREMBITS LESSINT 8 PUSHCONT { - .loc stdlib.sol, 234 + .loc stdlib.sol, 272 NEWC PUSH S3 PAIR @@ -874,7 +1037,7 @@ .loc stdlib.sol, 0 } IF - .loc stdlib.sol, 236 + .loc stdlib.sol, 274 PUSH S2 UNPAIR PUSHINT 46 @@ -884,7 +1047,7 @@ PAIR POP S3 SWAP - .loc stdlib.sol, 237 + .loc stdlib.sol, 275 TRUE CALLREF { .inline __convertIntToString @@ -935,16 +1098,16 @@ } .fragment __stackReverse, { - .loc stdlib.sol, 606 + .loc stdlib.sol, 644 NULL - .loc stdlib.sol, 607 + .loc stdlib.sol, 645 PUSHCONT { OVER ISNULL NOT } PUSHCONT { - .loc stdlib.sol, 608 + .loc stdlib.sol, 646 OVER UNPAIR POP S3 @@ -953,61 +1116,61 @@ .loc stdlib.sol, 0 } WHILE - .loc stdlib.sol, 609 + .loc stdlib.sol, 647 NIP .loc stdlib.sol, 0 } .fragment __stackSort, { - .loc stdlib.sol, 564 + .loc stdlib.sol, 602 OVER ISNULL PUSHCONT { - .loc stdlib.sol, 565 + .loc stdlib.sol, 603 DROP2 NULL .loc stdlib.sol, 0 } IFJMP - .loc stdlib.sol, 568 + .loc stdlib.sol, 606 NULL - .loc stdlib.sol, 569 + .loc stdlib.sol, 607 PUSHINT 0 - .loc stdlib.sol, 570 + .loc stdlib.sol, 608 PUSHCONT { PUSH S3 ISNULL NOT } PUSHCONT { - .loc stdlib.sol, 572 + .loc stdlib.sol, 610 PUSH S3 UNPAIR POP S5 NULL PAIR - .loc stdlib.sol, 573 + .loc stdlib.sol, 611 PUSH S2 PAIR POP S2 - .loc stdlib.sol, 570 + .loc stdlib.sol, 608 INC .loc stdlib.sol, 0 } WHILE - .loc stdlib.sol, 576 + .loc stdlib.sol, 614 PUSHCONT { DUP GTINT 1 } PUSHCONT { - .loc stdlib.sol, 577 + .loc stdlib.sol, 615 NULL - .loc stdlib.sol, 578 + .loc stdlib.sol, 616 OVER MODPOW2 1 PUSHCONT { - .loc stdlib.sol, 579 + .loc stdlib.sol, 617 PUSH S2 UNPAIR POP S4 @@ -1016,22 +1179,22 @@ .loc stdlib.sol, 0 } IF - .loc stdlib.sol, 580 + .loc stdlib.sol, 618 PUSHCONT { PUSH S2 ISNULL NOT } PUSHCONT { - .loc stdlib.sol, 581 + .loc stdlib.sol, 619 NULL - .loc stdlib.sol, 582 + .loc stdlib.sol, 620 PUSH S3 UNPAIR - .loc stdlib.sol, 583 + .loc stdlib.sol, 621 UNPAIR POP S6 - .loc stdlib.sol, 584 + .loc stdlib.sol, 622 PUSHCONT { OVER ISNULL @@ -1042,7 +1205,7 @@ AND } PUSHCONT { - .loc stdlib.sol, 585 + .loc stdlib.sol, 623 OVER FIRST OVER @@ -1051,13 +1214,13 @@ PUSH C3 CALLX PUSHCONT { - .loc stdlib.sol, 586 + .loc stdlib.sol, 624 BLKPUSH 2, 2 UNPAIR POP S4 } PUSHCONT { - .loc stdlib.sol, 588 + .loc stdlib.sol, 626 PUSH2 S2, S0 UNPAIR POP S3 @@ -1069,14 +1232,14 @@ .loc stdlib.sol, 0 } WHILE - .loc stdlib.sol, 590 + .loc stdlib.sol, 628 PUSHCONT { OVER ISNULL NOT } PUSHCONT { - .loc stdlib.sol, 591 + .loc stdlib.sol, 629 BLKPUSH 2, 2 UNPAIR POP S4 @@ -1086,14 +1249,14 @@ .loc stdlib.sol, 0 } WHILE - .loc stdlib.sol, 592 + .loc stdlib.sol, 630 PUSHCONT { DUP ISNULL NOT } PUSHCONT { - .loc stdlib.sol, 593 + .loc stdlib.sol, 631 PUSH2 S2, S0 UNPAIR POP S3 @@ -1103,26 +1266,26 @@ .loc stdlib.sol, 0 } WHILE - .loc stdlib.sol, 594 + .loc stdlib.sol, 632 DROP2 CALLREF { .inline __stackReverse } - .loc stdlib.sol, 595 + .loc stdlib.sol, 633 SWAP PAIR .loc stdlib.sol, 0 } WHILE - .loc stdlib.sol, 597 + .loc stdlib.sol, 635 POP S2 - .loc stdlib.sol, 598 + .loc stdlib.sol, 636 INC RSHIFT 1 .loc stdlib.sol, 0 } WHILE - .loc stdlib.sol, 600 + .loc stdlib.sol, 638 DROP UNPAIR DROP @@ -1131,28 +1294,28 @@ } .fragment __strstr, { - .loc stdlib.sol, 461 + .loc stdlib.sol, 499 NULL - .loc stdlib.sol, 462 + .loc stdlib.sol, 500 PUSH S2 CTOS - .loc stdlib.sol, 463 + .loc stdlib.sol, 501 PUSH S2 CTOS - .loc stdlib.sol, 464 + .loc stdlib.sol, 502 PUSHINT 0 FALSE ; decl return flag PUSHCONT { - .loc stdlib.sol, 465 + .loc stdlib.sol, 503 OVER2 PUSHCONT { - .loc stdlib.sol, 437 + .loc stdlib.sol, 475 OVER SBITS - .loc stdlib.sol, 438 + .loc stdlib.sol, 476 OVER SBITS - .loc stdlib.sol, 439 + .loc stdlib.sol, 477 FALSE ; decl return flag PUSHCONT { PUSH S3 @@ -1160,10 +1323,10 @@ NOT } PUSHCONT { - .loc stdlib.sol, 440 + .loc stdlib.sol, 478 PUSH S2 PUSHCONT { - .loc stdlib.sol, 441 + .loc stdlib.sol, 479 PUSH S4 SREFS PUSHCONT { @@ -1173,43 +1336,43 @@ RETALT } IFNOTJMP - .loc stdlib.sol, 443 + .loc stdlib.sol, 481 PUSH S4 LDREFRTOS XCPU S6, S6 BLKDROP2 2, 1 - .loc stdlib.sol, 444 + .loc stdlib.sol, 482 SBITS POP S3 .loc stdlib.sol, 0 } IFNOT - .loc stdlib.sol, 446 + .loc stdlib.sol, 484 OVER PUSHCONT { - .loc stdlib.sol, 447 + .loc stdlib.sol, 485 PUSH S3 LDREFRTOS XCPU S5, S5 BLKDROP2 2, 1 - .loc stdlib.sol, 448 + .loc stdlib.sol, 486 SBITS POP S2 .loc stdlib.sol, 0 } IFNOT - .loc stdlib.sol, 450 + .loc stdlib.sol, 488 BLKPUSH 2, 2 MIN - .loc stdlib.sol, 451 + .loc stdlib.sol, 489 PUSH2 S5, S0 LDSLICEX POP S7 - .loc stdlib.sol, 452 + .loc stdlib.sol, 490 PUSH2 S5, S1 LDSLICEX POP S7 - .loc stdlib.sol, 453 + .loc stdlib.sol, 491 SDEQ PUSHCONT { BLKDROP 6 @@ -1218,11 +1381,11 @@ RETALT } IFNOTJMP - .loc stdlib.sol, 455 + .loc stdlib.sol, 493 PUSH2 S3, S0 SUB POP S4 - .loc stdlib.sol, 456 + .loc stdlib.sol, 494 PUSH S2 SUBR POP S2 @@ -1230,10 +1393,10 @@ } WHILEBRK IFRET - .loc stdlib.sol, 458 + .loc stdlib.sol, 496 BLKDROP 4 TRUE - .loc stdlib.sol, 436 + .loc stdlib.sol, 474 } CALLX .loc stdlib.sol, 0 @@ -1244,15 +1407,15 @@ RETALT } IFJMP - .loc stdlib.sol, 467 + .loc stdlib.sol, 505 PUSH S3 SEMPTY IFRETALT - .loc stdlib.sol, 469 + .loc stdlib.sol, 507 PUSH S3 SBITS PUSHCONT { - .loc stdlib.sol, 470 + .loc stdlib.sol, 508 PUSH S3 LDREFRTOS NIP @@ -1260,12 +1423,12 @@ .loc stdlib.sol, 0 } IFNOT - .loc stdlib.sol, 471 + .loc stdlib.sol, 509 PUSH S3 LDU 8 XCPU S5, S3 BLKDROP2 2, 1 - .loc stdlib.sol, 472 + .loc stdlib.sol, 510 INC POP S2 .loc stdlib.sol, 0 @@ -1274,15 +1437,15 @@ EQINT 4 IFRET BLKDROP 6 - .loc stdlib.sol, 474 + .loc stdlib.sol, 512 NULL .loc stdlib.sol, 0 } .fragment __toLowerCase, { - .loc stdlib.sol, 479 + .loc stdlib.sol, 517 .inline __createStringBuilder - .loc stdlib.sol, 480 + .loc stdlib.sol, 518 SWAP CTOS NULL @@ -1302,18 +1465,18 @@ IFNOT BLKDROP2 2, 2 XCPU2 S1, S0, S0 - .loc stdlib.sol, 482 + .loc stdlib.sol, 520 GTINT 64 OVER LESSINT 91 AND PUSHCONT { - .loc stdlib.sol, 483 + .loc stdlib.sol, 521 ADDCONST 32 .loc stdlib.sol, 0 } IF - .loc stdlib.sol, 484 + .loc stdlib.sol, 522 PUXC S3, S-1 CALLREF { .inline __appendBytes1 @@ -1323,7 +1486,7 @@ } WHILE DROP2 - .loc stdlib.sol, 486 + .loc stdlib.sol, 524 CALLREF { .inline __makeString } @@ -1331,9 +1494,9 @@ } .fragment __toUpperCase, { - .loc stdlib.sol, 491 + .loc stdlib.sol, 529 .inline __createStringBuilder - .loc stdlib.sol, 492 + .loc stdlib.sol, 530 SWAP CTOS NULL @@ -1353,18 +1516,18 @@ IFNOT BLKDROP2 2, 2 XCPU2 S1, S0, S0 - .loc stdlib.sol, 494 + .loc stdlib.sol, 532 GTINT 96 OVER LESSINT 123 AND PUSHCONT { - .loc stdlib.sol, 495 + .loc stdlib.sol, 533 ADDCONST -32 .loc stdlib.sol, 0 } IF - .loc stdlib.sol, 496 + .loc stdlib.sol, 534 PUXC S3, S-1 CALLREF { .inline __appendBytes1 @@ -1374,7 +1537,7 @@ } WHILE DROP2 - .loc stdlib.sol, 498 + .loc stdlib.sol, 536 CALLREF { .inline __makeString } @@ -1521,20 +1684,20 @@ } .fragment __stoi, { - .loc stdlib.sol, 302 + .loc stdlib.sol, 340 CTOS - .loc stdlib.sol, 303 + .loc stdlib.sol, 341 DUP SBITS LESSINT 8 PUSHCONT { - .loc stdlib.sol, 304 + .loc stdlib.sol, 342 DROP NULL .loc stdlib.sol, 0 } IFJMP - .loc stdlib.sol, 307 + .loc stdlib.sol, 345 DUP SBITS GTINT 7 @@ -1546,10 +1709,10 @@ EQINT 45 } IF - .loc stdlib.sol, 308 + .loc stdlib.sol, 346 DUP PUSHCONT { - .loc stdlib.sol, 309 + .loc stdlib.sol, 347 OVER PUSHINT 8 SDSKIPFIRST @@ -1557,7 +1720,7 @@ .loc stdlib.sol, 0 } IF - .loc stdlib.sol, 311 + .loc stdlib.sol, 349 OVER SBITS GTINT 15 @@ -1570,10 +1733,10 @@ EQUAL } IF - .loc stdlib.sol, 312 + .loc stdlib.sol, 350 DUP PUSHCONT { - .loc stdlib.sol, 313 + .loc stdlib.sol, 351 PUSH S2 PUSHINT 16 SDSKIPFIRST @@ -1581,36 +1744,36 @@ .loc stdlib.sol, 0 } IF - .loc stdlib.sol, 315 + .loc stdlib.sol, 353 PUSHINT 0 - .loc stdlib.sol, 316 + .loc stdlib.sol, 354 PUSH S3 SBITS RSHIFT 3 - .loc stdlib.sol, 317 + .loc stdlib.sol, 355 FALSE ; decl return flag ROLL 3 PUSHCONT { - .loc stdlib.sol, 318 + .loc stdlib.sol, 356 FALSE ; decl return flag PUSH S2 PUSHCONT { - .loc stdlib.sol, 319 + .loc stdlib.sol, 357 PUSH S5 LDU 8 POP S7 - .loc stdlib.sol, 320 + .loc stdlib.sol, 358 PUSH S4 MULCONST 16 POP S5 - .loc stdlib.sol, 321 + .loc stdlib.sol, 359 DUP GTINT 47 OVER LESSINT 58 AND PUSHCONT { - .loc stdlib.sol, 322 + .loc stdlib.sol, 360 DUP ADDCONST -48 PUSH S5 @@ -1625,7 +1788,7 @@ LESSINT 71 AND PUSHCONT { - .loc stdlib.sol, 324 + .loc stdlib.sol, 362 DUP ADDCONST -55 PUSH S5 @@ -1640,7 +1803,7 @@ LESSINT 103 AND PUSHCONT { - .loc stdlib.sol, 326 + .loc stdlib.sol, 364 DUP ADDCONST -87 PUSH S5 @@ -1649,7 +1812,7 @@ .loc stdlib.sol, 0 } PUSHCONT { - .loc stdlib.sol, 328 + .loc stdlib.sol, 366 BLKDROP 7 NULL PUSHINT 4 @@ -1671,15 +1834,15 @@ .loc stdlib.sol, 0 } PUSHCONT { - .loc stdlib.sol, 332 + .loc stdlib.sol, 370 FALSE ; decl return flag PUSH S2 PUSHCONT { - .loc stdlib.sol, 333 + .loc stdlib.sol, 371 PUSH S5 LDU 8 POP S7 - .loc stdlib.sol, 334 + .loc stdlib.sol, 372 DUP LESSINT 48 OVER @@ -1692,7 +1855,7 @@ RETALT } IFJMP - .loc stdlib.sol, 336 + .loc stdlib.sol, 374 PUSH S4 MULCONST 10 SWAP @@ -1709,51 +1872,51 @@ } IFELSE IFRET - .loc stdlib.sol, 339 + .loc stdlib.sol, 377 DROP SWAP PUSHCONT { - .loc stdlib.sol, 340 + .loc stdlib.sol, 378 NEGATE .loc stdlib.sol, 0 } IF - .loc stdlib.sol, 341 + .loc stdlib.sol, 379 NIP .loc stdlib.sol, 0 } .fragment __compareStrings, { - .loc stdlib.sol, 389 + .loc stdlib.sol, 427 SWAP CTOS - .loc stdlib.sol, 390 + .loc stdlib.sol, 428 SWAP CTOS - .loc stdlib.sol, 391 + .loc stdlib.sol, 429 FALSE ; decl return flag PUSHCONT { - .loc stdlib.sol, 392 + .loc stdlib.sol, 430 BLKPUSH 2, 2 SDLEXCMP - .loc stdlib.sol, 393 + .loc stdlib.sol, 431 DUP PUSHCONT { - .loc stdlib.sol, 394 + .loc stdlib.sol, 432 BLKDROP2 3, 1 PUSHINT 4 RETALT .loc stdlib.sol, 0 } IFJMP - .loc stdlib.sol, 396 + .loc stdlib.sol, 434 DROP PUSH S2 SREFS - .loc stdlib.sol, 397 + .loc stdlib.sol, 435 PUSH S2 SREFS - .loc stdlib.sol, 398 + .loc stdlib.sol, 436 DUP2 GREATER PUSHCONT { @@ -1763,7 +1926,7 @@ RETALT } IFJMP - .loc stdlib.sol, 400 + .loc stdlib.sol, 438 PUSH2 S0, S1 GREATER PUSHCONT { @@ -1773,7 +1936,7 @@ RETALT } IFJMP - .loc stdlib.sol, 402 + .loc stdlib.sol, 440 ADD PUSHCONT { BLKDROP 3 @@ -1782,12 +1945,12 @@ RETALT } IFNOTJMP - .loc stdlib.sol, 404 + .loc stdlib.sol, 442 PUSH S2 LDREFRTOS XCPU S4, S3 BLKDROP2 2, 1 - .loc stdlib.sol, 405 + .loc stdlib.sol, 443 LDREFRTOS NIP POP S2 @@ -1795,18 +1958,18 @@ } AGAINBRK IFRET - .loc stdlib.sol, 407 + .loc stdlib.sol, 445 DROP2 PUSHINT 0 .loc stdlib.sol, 0 } .fragment __strchr, { - .loc stdlib.sol, 417 + .loc stdlib.sol, 455 NULL - .loc stdlib.sol, 418 + .loc stdlib.sol, 456 PUSHINT 0 - .loc stdlib.sol, 419 + .loc stdlib.sol, 457 ROLL 3 CTOS NULL @@ -1827,7 +1990,7 @@ IFNOT BLKDROP2 2, 3 XCPU2 S2, S1, S5 - .loc stdlib.sol, 420 + .loc stdlib.sol, 458 EQUAL PUSHCONT { XCHG S3 @@ -1836,7 +1999,7 @@ RETALT } IFJMP - .loc stdlib.sol, 422 + .loc stdlib.sol, 460 PUSH S3 INC POP S4 @@ -1850,11 +2013,11 @@ } .fragment __strrchr, { - .loc stdlib.sol, 426 + .loc stdlib.sol, 464 NULL - .loc stdlib.sol, 427 + .loc stdlib.sol, 465 PUSHINT 0 - .loc stdlib.sol, 428 + .loc stdlib.sol, 466 ROLL 3 CTOS NULL @@ -1874,16 +2037,16 @@ IFNOT BLKDROP2 2, 2 XCPU2 S1, S0, S4 - .loc stdlib.sol, 429 + .loc stdlib.sol, 467 EQUAL PUSHCONT { - .loc stdlib.sol, 430 + .loc stdlib.sol, 468 PUSH S2 POP S4 .loc stdlib.sol, 0 } IF - .loc stdlib.sol, 431 + .loc stdlib.sol, 469 PUSH S2 INC POP S3 @@ -1896,21 +2059,21 @@ } .fragment __stateInitHash, { - .loc stdlib.sol, 503 + .loc stdlib.sol, 541 NEWC - .loc stdlib.sol, 505 + .loc stdlib.sol, 543 STSLICECONST x020134 - .loc stdlib.sol, 517 + .loc stdlib.sol, 555 ROT STUR 16 - .loc stdlib.sol, 518 + .loc stdlib.sol, 556 STU 16 - .loc stdlib.sol, 520 + .loc stdlib.sol, 558 ROT STUR 256 - .loc stdlib.sol, 521 + .loc stdlib.sol, 559 STU 256 - .loc stdlib.sol, 522 + .loc stdlib.sol, 560 ENDC CTOS SHA256U @@ -1918,23 +2081,23 @@ } .fragment __forwardFee, { - .loc stdlib.sol, 526 + .loc stdlib.sol, 564 DEPTH ADDCONST -3 PICK CTOS - .loc stdlib.sol, 527 + .loc stdlib.sol, 565 LDU 1 SWAP - .loc stdlib.sol, 528 + .loc stdlib.sol, 566 PUSHCONT { - .loc stdlib.sol, 539 + .loc stdlib.sol, 577 DROP PUSHINT 0 .loc stdlib.sol, 0 } PUSHCONT { - .loc stdlib.sol, 533 + .loc stdlib.sol, 571 LDU 3 LDMSGADDR LDMSGADDR @@ -1942,7 +2105,7 @@ LDDICT LDVARUINT16 BLKDROP2 6, 1 - .loc stdlib.sol, 537 + .loc stdlib.sol, 575 LDVARUINT16 DROP .loc stdlib.sol, 0 @@ -1952,28 +2115,28 @@ } .fragment __importFee, { - .loc stdlib.sol, 544 + .loc stdlib.sol, 582 DEPTH ADDCONST -3 PICK CTOS - .loc stdlib.sol, 545 + .loc stdlib.sol, 583 LDU 2 SWAP - .loc stdlib.sol, 546 + .loc stdlib.sol, 584 EQINT 2 PUSHCONT { - .loc stdlib.sol, 549 + .loc stdlib.sol, 587 LDMSGADDR LDMSGADDR BLKDROP2 2, 1 - .loc stdlib.sol, 550 + .loc stdlib.sol, 588 LDVARUINT16 DROP .loc stdlib.sol, 0 } PUSHCONT { - .loc stdlib.sol, 552 + .loc stdlib.sol, 590 DROP PUSHINT 0 .loc stdlib.sol, 0 @@ -1983,7 +2146,7 @@ } .fragment __qand, { - .loc stdlib.sol, 613 + .loc stdlib.sol, 651 OVER ISNAN DUP @@ -2015,14 +2178,14 @@ QAND } IFJMP - .loc stdlib.sol, 617 + .loc stdlib.sol, 655 DROP2 PUSHINT 0 .loc stdlib.sol, 0 } .fragment __qor, { - .loc stdlib.sol, 621 + .loc stdlib.sol, 659 OVER ISNAN DUP @@ -2054,7 +2217,7 @@ QOR } IFJMP - .loc stdlib.sol, 625 + .loc stdlib.sol, 663 DROP2 PUSHINT -1 .loc stdlib.sol, 0 diff --git a/sold/Cargo.toml b/sold/Cargo.toml index 95e4ffc4..853365e1 100644 --- a/sold/Cargo.toml +++ b/sold/Cargo.toml @@ -1,7 +1,7 @@ [package] edition = '2021' name = 'sold' -version = '0.76.0' +version = '0.77.0' [[bin]] name = 'sold' @@ -16,9 +16,9 @@ serde_json = { features = [ 'unbounded_depth' ], version = '1.0' } strip-ansi-escapes = '0.2' clap = { features = [ 'derive' ], version = '4.5' } serde = { features = [ 'derive' ], version = '1.0' } -ever_abi = { git = 'https://github.com/everx-labs/ever-abi.git', tag = '2.6.1' } -ever_block = { git = 'https://github.com/everx-labs/ever-block.git', tag = '1.11.0' } -ever_assembler = { features = [ 'gosh' ], git = 'https://github.com/everx-labs/ever-assembler.git', tag = '1.6.3' } +ever_abi = { git = 'https://github.com/everx-labs/ever-abi.git', tag = '2.7.2' } +ever_block = { git = 'https://github.com/everx-labs/ever-block.git', tag = '1.11.11' } +ever_assembler = { features = [ 'gosh' ], git = 'https://github.com/everx-labs/ever-assembler.git', tag = '1.6.14' } [build-dependencies] cmake = '0.1' diff --git a/sold/build.rs b/sold/build.rs index abd3eef2..f6a877b8 100644 --- a/sold/build.rs +++ b/sold/build.rs @@ -28,7 +28,7 @@ fn full_lib_name(lib_name: &str, boost_lib_dir: &str) -> String { let mut file_name = file.unwrap().file_name().to_str().unwrap().to_string(); if file_name.starts_with(lib_name) { if file_name.ends_with(".lib") { - file_name = file_name.get(0..file_name.len()-4).unwrap().to_string(); + file_name = file_name.get(0..file_name.len() - 4).unwrap().to_string(); } return file_name.to_string(); } @@ -54,27 +54,45 @@ fn main() { for lib in ["solc", "solidity", "langutil", "solutil"] { if cfg!(target_os = "windows") { - println!("cargo:rustc-link-search=native={}/build/lib{}/{}", sol2tvm.display(), lib, profile); + println!( + "cargo:rustc-link-search=native={}/build/lib{}/{}", + sol2tvm.display(), + lib, + profile + ); } else { - println!("cargo:rustc-link-search=native={}/build/lib{}", sol2tvm.display(), lib); + println!( + "cargo:rustc-link-search=native={}/build/lib{}", + sol2tvm.display(), + lib + ); } println!("cargo:rustc-link-lib=static={}", lib); } println!("cargo:rustc-link-search=native={}/lib", sol2tvm.display()); - println!("cargo:rustc-link-search=native={}/build/deps/lib", sol2tvm.display()); + println!( + "cargo:rustc-link-search=native={}/build/deps/lib", + sol2tvm.display() + ); let boost_lib_dir = "../compiler/deps/boost/lib"; if cfg!(target_os = "windows") { - println!("cargo:rustc-link-search=native={}", absolute_path(boost_lib_dir)); + println!( + "cargo:rustc-link-search=native={}", + absolute_path(boost_lib_dir) + ); } else if cfg!(target_os = "macos") { match std::env::var("HOMEBREW") { Ok(homebrew) => { - assert!(std::path::PathBuf::from(homebrew.to_string()).exists(), "Set correct $HOMEBREW!"); + assert!( + std::path::PathBuf::from(homebrew.to_string()).exists(), + "Set correct $HOMEBREW!" + ); println!("cargo:rustc-link-search=native={}/lib", homebrew) } // use default path - Err(_) => println!("cargo:rustc-link-search=native=/opt/homebrew/lib") + Err(_) => println!("cargo:rustc-link-search=native=/opt/homebrew/lib"), } println!("cargo:rustc-link-search=native=/usr/local/lib"); } else if cfg!(target_os = "freebsd") { diff --git a/sold/src/lib.rs b/sold/src/lib.rs index b902681b..8d2e956c 100644 --- a/sold/src/lib.rs +++ b/sold/src/lib.rs @@ -4,12 +4,12 @@ use std::io::Write; use std::os::raw::{c_char, c_void}; use std::path::Path; -use clap::{ValueEnum, Parser}; use anyhow::{bail, format_err}; +use clap::{Parser, ValueEnum}; use serde::Deserialize; -use ever_block::{Result, Status}; use ever_assembler::{DbgInfo, Engine, Units}; +use ever_block::{Result, Status}; mod libsolc; mod printer; @@ -26,7 +26,7 @@ unsafe extern "C" fn read_callback( .into_owned(); if kind != "source" { *o_error = make_error(format!("Unknown kind \"{}\"", kind)); - return + return; } let mut success = 0i32; let contents_ptr = libsolc::file_reader_read(context, data, &mut success); @@ -55,7 +55,11 @@ fn to_cstr(s: &str) -> Result { std::ffi::CString::new(s).map_err(|e| format_err!("Failed to convert: {}", e)) } -fn compile(args: &Args, input: &str, remappings: Vec) -> Result<(String, serde_json::Value)> { +fn compile( + args: &Args, + input: &str, + remappings: Vec, +) -> Result<(String, serde_json::Value)> { let file_reader = unsafe { let file_reader = libsolc::file_reader_new(); if let Some(base_path) = args.base_path.clone() { @@ -71,10 +75,12 @@ fn compile(args: &Args, input: &str, remappings: Vec) -> Result<(String, libsolc::file_reader_add_or_update_file( file_reader, to_cstr(input)?.as_ptr(), - to_cstr(&input_content)?.as_ptr() + to_cstr(&input_content)?.as_ptr(), ); if let Some(path) = dunce::canonicalize(Path::new(&input))?.parent() { - let path = path.to_str().ok_or_else(|| format_err!("Failed to convert path to string"))?; + let path = path + .to_str() + .ok_or_else(|| format_err!("Failed to convert path to string"))?; libsolc::file_reader_allow_directory(file_reader, to_cstr(path)?.as_ptr()); } file_reader @@ -82,7 +88,9 @@ fn compile(args: &Args, input: &str, remappings: Vec) -> Result<(String, let source_unit_name = { let name = unsafe { std::ffi::CStr::from_ptr(libsolc::file_reader_source_unit_name( - file_reader, to_cstr(input)?.as_ptr())) + file_reader, + to_cstr(input)?.as_ptr(), + )) }; &name.to_string_lossy().into_owned() }; @@ -107,16 +115,15 @@ fn compile(args: &Args, input: &str, remappings: Vec) -> Result<(String, "" }; let tvm_version = match args.tvm_version { - None => { - "".to_string() - } + None => "".to_string(), Some(version) => { format!(r#""tvmVersion": "{}","#, version) } }; let main_contract = args.contract.clone().unwrap_or_default(); let remappings = remappings_to_json_string(remappings); - let input_json = format!(r#" + let input_json = format!( + r#" {{ "language": "Solidity", "settings": {{ @@ -136,7 +143,8 @@ fn compile(args: &Args, input: &str, remappings: Vec) -> Result<(String, }} }} }} - "#); + "# + ); let output = unsafe { std::ffi::CStr::from_ptr(libsolc::solidity_compile( to_cstr(&input_json)?.as_ptr(), @@ -183,20 +191,20 @@ fn parse_comp_result( // println!("{}", serde_json::to_string_pretty(&res)?); if let Some(v) = res.get("errors") { - let entries = v.as_array() - .ok_or_else(|| parse_error!())?; + let entries = v.as_array().ok_or_else(|| parse_error!())?; let mut severe = false; for entry in entries { - let entry = entry.as_object() - .ok_or_else(|| parse_error!())?; - let severity = entry.get("severity") + let entry = entry.as_object().ok_or_else(|| parse_error!())?; + let severity = entry + .get("severity") .ok_or_else(|| parse_error!())? .as_str() .ok_or_else(|| parse_error!())?; if severity == "error" { severe = true; } - let message = entry.get("humanFormattedMessage") + let message = entry + .get("humanFormattedMessage") .ok_or_else(|| parse_error!())? .as_str() .ok_or_else(|| parse_error!())?; @@ -225,26 +233,28 @@ fn parse_comp_result( if let Some(ref contract) = contract { if !all.contains_key(contract) { - Err(format_err!("Source file doesn't contain the desired contract \"{}\"", contract)) + Err(format_err!( + "Source file doesn't contain the desired contract \"{}\"", + contract + )) } else { Ok(all.get(contract).unwrap().clone()) } } else { - let mut iter = - all.iter().filter(|(_, v)| { - if !compile { - true - } else if let Some(v) = v.as_object() { - let assembly = v.get("assembly"); - if let Some(assembly) = assembly { - !assembly.is_null() - } else { - false - } + let mut iter = all.iter().filter(|(_, v)| { + if !compile { + true + } else if let Some(v) = v.as_object() { + let assembly = v.get("assembly"); + if let Some(assembly) = assembly { + !assembly.is_null() } else { false } - }); + } else { + false + } + }); let qualification = if compile { "deployable " } else { "" }; let entry = iter.next(); if let Some(entry) = entry { @@ -263,7 +273,7 @@ static STDLIB: &str = include_str!("../../lib/stdlib_sol.tvm"); fn parse_positional_args(args: Vec) -> Result<(String, Vec)> { let mut input = None; - let mut remappings = vec!(); + let mut remappings = vec![]; for arg in args { if arg.contains('=') { remappings.push(arg); @@ -293,7 +303,10 @@ pub fn build(args: Args) -> Status { if let Some(ref output_prefix) = args.output_prefix { if output_prefix.contains(std::path::is_separator) { - bail!("Invalid output prefix \"{}\". Use option -O to set output directory", output_prefix); + bail!( + "Invalid output prefix \"{}\". Use option -O to set output directory", + output_prefix + ); } } @@ -305,20 +318,24 @@ pub fn build(args: Args) -> Status { &res.1, &res.0, args.contract, - !(args.abi_json || args.ast_compact_json || args.userdoc || args.devdoc ) + !(args.abi_json || args.ast_compact_json || args.userdoc || args.devdoc), )?; if args.function_ids { println!("{}", serde_json::to_string_pretty(&out["functionIds"])?); - return Ok(()) + return Ok(()); } if args.private_function_ids { - println!("{}", serde_json::to_string_pretty(&out["privateFunctionIds"])?); - return Ok(()) + println!( + "{}", + serde_json::to_string_pretty(&out["privateFunctionIds"])? + ); + return Ok(()); } - let input_file_stem = input_canonical.file_stem() + let input_file_stem = input_canonical + .file_stem() .ok_or_else(|| format_err!("Failed to extract file stem"))? .to_str() .ok_or_else(|| format_err!("Failed to get file stem"))? @@ -335,18 +352,20 @@ pub fn build(args: Args) -> Status { println!("User Documentation"); println!("{}", serde_json::to_string_pretty(&out["userdoc"])?); } - return Ok(()) + return Ok(()); } if args.ast_compact_json { - let all = res.1.as_object() + let all = res + .1 + .as_object() .ok_or_else(|| parse_error!())? .get("sources") .ok_or_else(|| parse_error!())? .as_object() .ok_or_else(|| parse_error!())?; - let mut array = vec!(); + let mut array = vec![]; for (_, val) in all { let ast = val .as_object() @@ -357,7 +376,7 @@ pub fn build(args: Args) -> Status { } assert_eq!(array.len(), 1); println!("{}", serde_json::to_string(&array[0])?); - return Ok(()) + return Ok(()); } let abi = &out["abi"]; @@ -365,7 +384,7 @@ pub fn build(args: Args) -> Status { let mut abi_file = File::create(output_path.join(abi_file_name))?; printer::print_abi_json_canonically(&mut abi_file, abi)?; if args.abi_json { - return Ok(()) + return Ok(()); } let assembly = out["assembly"] @@ -389,7 +408,8 @@ pub fn build(args: Args) -> Status { let mut units = Units::new(); for (input, filename) in inputs { engine.reset(filename); - units = engine.compile_toplevel(&input) + units = engine + .compile_toplevel(&input) .map_err(|e| format_err!("{}", e))?; } let (b, d) = units.finalize(); diff --git a/sold/src/main.rs b/sold/src/main.rs index c0780d1c..3ad16805 100644 --- a/sold/src/main.rs +++ b/sold/src/main.rs @@ -11,7 +11,7 @@ */ use clap::Parser; -use sold_lib::{Args, VERSION, ERROR_MSG_NO_OUTPUT, build, solidity_version}; +use sold_lib::{build, solidity_version, Args, ERROR_MSG_NO_OUTPUT, VERSION}; mod libsolc; diff --git a/sold/src/printer.rs b/sold/src/printer.rs index 50a90c8a..5600cd1c 100644 --- a/sold/src/printer.rs +++ b/sold/src/printer.rs @@ -19,7 +19,9 @@ use serde::Serialize; use ever_block::{Result, Status}; pub fn print_abi_json_canonically(out: &mut File, value: &serde_json::Value) -> Status { - let root = value.as_object().ok_or_else(|| format_err!("ABI parsing failed"))?; + let root = value + .as_object() + .ok_or_else(|| format_err!("ABI parsing failed"))?; writeln!(out, "{{")?; writeln!(out, "\t\"ABI version\": {},", root["ABI version"])?; if let Some(version) = root.get("version") { @@ -27,7 +29,9 @@ pub fn print_abi_json_canonically(out: &mut File, value: &serde_json::Value) -> } if let Some(header) = root.get("header") { write!(out, "\t\"header\": [")?; - let array = header.as_array().ok_or_else(|| format_err!("ABI parsing failed"))?; + let array = header + .as_array() + .ok_or_else(|| format_err!("ABI parsing failed"))?; for i in 0..array.len() { write!(out, "{}", array[i])?; if i + 1 != array.len() { @@ -41,6 +45,10 @@ pub fn print_abi_json_canonically(out: &mut File, value: &serde_json::Value) -> print(out, &root["functions"])?; writeln!(out, "\t],")?; + writeln!(out, "\t\"getters\": [")?; + print(out, &root["getters"])?; + writeln!(out, "\t],")?; + writeln!(out, "\t\"events\": [")?; print(out, &root["events"])?; writeln!(out, "\t],")?; @@ -54,7 +62,9 @@ pub fn print_abi_json_canonically(out: &mut File, value: &serde_json::Value) -> } fn print_data(out: &mut File, value: &serde_json::Value) -> Status { - let json = value.as_array().ok_or_else(|| format_err!("ABI parsing failed"))?; + let json = value + .as_array() + .ok_or_else(|| format_err!("ABI parsing failed"))?; for f in 0..json.len() { write!(out, "\t\t")?; @@ -82,9 +92,13 @@ fn print_array(out: &mut File, array: &[serde_json::Value]) -> Status { } fn print(out: &mut File, value: &serde_json::Value) -> Status { - let json = value.as_array().ok_or_else(|| format_err!("ABI parsing failed"))?; + let json = value + .as_array() + .ok_or_else(|| format_err!("ABI parsing failed"))?; for f in 0..json.len() { - let function = json[f].as_object().ok_or_else(|| format_err!("ABI parsing failed"))?; + let function = json[f] + .as_object() + .ok_or_else(|| format_err!("ABI parsing failed"))?; writeln!(out, "\t\t{{")?; writeln!(out, "\t\t\t\"name\": {},", function["name"])?; @@ -95,14 +109,18 @@ fn print(out: &mut File, value: &serde_json::Value) -> Status { writeln!(out, "\t\t\t\"inputs\": [")?; if let Some(inputs) = function.get("inputs") { - let array = inputs.as_array().ok_or_else(|| format_err!("ABI parsing failed"))?; + let array = inputs + .as_array() + .ok_or_else(|| format_err!("ABI parsing failed"))?; print_array(out, array)?; } writeln!(out, "\t\t\t],")?; writeln!(out, "\t\t\t\"outputs\": [")?; if let Some(outputs) = function.get("outputs") { - let array = outputs.as_array().ok_or_else(|| format_err!("ABI parsing failed"))?; + let array = outputs + .as_array() + .ok_or_else(|| format_err!("ABI parsing failed"))?; print_array(out, array)?; } writeln!(out, "\t\t\t]")?; diff --git a/sold/tests/tests.rs b/sold/tests/tests.rs index 29956eab..071ea493 100644 --- a/sold/tests/tests.rs +++ b/sold/tests/tests.rs @@ -10,18 +10,18 @@ * See the GNU General Public License for more details at: https://www.gnu.org/licenses/gpl-3.0.html */ -use predicates::prelude::*; use assert_cmd::Command; +use predicates::prelude::*; use sold_lib::ERROR_MSG_NO_OUTPUT; type Status = Result<(), Box>; const BIN_NAME: &str = "sold"; fn remove_all_outputs(name: &str) -> Status { - std::fs::remove_file(format!("tests/{}.abi.json", name))?; - std::fs::remove_file(format!("tests/{}.code", name))?; + std::fs::remove_file(format!("tests/{}.abi.json", name))?; + std::fs::remove_file(format!("tests/{}.code", name))?; std::fs::remove_file(format!("tests/{}.debug.json", name))?; - std::fs::remove_file(format!("tests/{}.tvc", name))?; + std::fs::remove_file(format!("tests/{}.tvc", name))?; Ok(()) } @@ -91,8 +91,7 @@ fn test_library() -> Status { .arg("tests") .assert() .success() - .stderr(predicate::str::contains(ERROR_MSG_NO_OUTPUT)) - ; + .stderr(predicate::str::contains(ERROR_MSG_NO_OUTPUT)); Ok(()) } @@ -147,7 +146,8 @@ fn test_private_function_ids() -> Status { .arg("--private-function-ids") .assert() .success() - .stdout(predicate::str::contains(r#"[ + .stdout(predicate::str::contains( + r#"[ { "id": 5581, "scope": "C", @@ -168,7 +168,8 @@ fn test_private_function_ids() -> Status { "scope": "Math", "sign": "mul(uint256,uint256)" } -"#)); +"#, + )); Ok(()) } @@ -194,7 +195,8 @@ fn test_userdoc_devdoc() -> Status { .arg("--devdoc") .assert() .success() - .stdout(predicate::str::contains(r#"Developer Documentation + .stdout(predicate::str::contains( + r#"Developer Documentation { "kind": "dev", "methods": {}, @@ -206,6 +208,7 @@ User Documentation "methods": {}, "version": 1 } -"#)); - Ok(()) +"#, + )); + Ok(()) }