From 5f43b8dbeba2c867b027a2dd80cc52da77b717dc Mon Sep 17 00:00:00 2001 From: Leonardo Alt Date: Wed, 30 Oct 2019 18:11:33 +0100 Subject: [PATCH] Output the storage layout of a contract via storageLayout artifact --- Changelog.md | 1 + docs/miscellaneous.rst | 265 ++++++++++++++++++ docs/using-the-compiler.rst | 3 + libsolidity/CMakeLists.txt | 2 + libsolidity/interface/CompilerStack.cpp | 23 ++ libsolidity/interface/CompilerStack.h | 9 + libsolidity/interface/StandardCompiler.cpp | 4 +- libsolidity/interface/StorageLayout.cpp | 119 ++++++++ libsolidity/interface/StorageLayout.h | 58 ++++ .../storage_layout_bytes/input.json | 16 ++ .../storage_layout_bytes/output.json | 4 + .../storage_layout_dyn_array/input.json | 16 ++ .../storage_layout_dyn_array/output.json | 4 + .../storage_layout_many/input.json | 16 ++ .../storage_layout_many/output.json | 4 + .../storage_layout_mapping/input.json | 16 ++ .../storage_layout_mapping/output.json | 4 + .../storage_layout_smoke/input.json | 16 ++ .../storage_layout_smoke/output.json | 4 + .../input.json | 19 ++ .../output.json | 4 + .../storage_layout_string/input.json | 16 ++ .../storage_layout_string/output.json | 4 + .../storage_layout_struct/input.json | 16 ++ .../storage_layout_struct/output.json | 4 + .../storage_layout_struct_packed/input.json | 16 ++ .../storage_layout_struct_packed/output.json | 4 + .../storage_layout_value_types/input.json | 16 ++ .../storage_layout_value_types/output.json | 4 + .../input.json | 16 ++ .../output.json | 4 + 31 files changed, 706 insertions(+), 1 deletion(-) create mode 100644 libsolidity/interface/StorageLayout.cpp create mode 100644 libsolidity/interface/StorageLayout.h create mode 100644 test/cmdlineTests/storage_layout_bytes/input.json create mode 100644 test/cmdlineTests/storage_layout_bytes/output.json create mode 100644 test/cmdlineTests/storage_layout_dyn_array/input.json create mode 100644 test/cmdlineTests/storage_layout_dyn_array/output.json create mode 100644 test/cmdlineTests/storage_layout_many/input.json create mode 100644 test/cmdlineTests/storage_layout_many/output.json create mode 100644 test/cmdlineTests/storage_layout_mapping/input.json create mode 100644 test/cmdlineTests/storage_layout_mapping/output.json create mode 100644 test/cmdlineTests/storage_layout_smoke/input.json create mode 100644 test/cmdlineTests/storage_layout_smoke/output.json create mode 100644 test/cmdlineTests/storage_layout_smoke_two_contracts/input.json create mode 100644 test/cmdlineTests/storage_layout_smoke_two_contracts/output.json create mode 100644 test/cmdlineTests/storage_layout_string/input.json create mode 100644 test/cmdlineTests/storage_layout_string/output.json create mode 100644 test/cmdlineTests/storage_layout_struct/input.json create mode 100644 test/cmdlineTests/storage_layout_struct/output.json create mode 100644 test/cmdlineTests/storage_layout_struct_packed/input.json create mode 100644 test/cmdlineTests/storage_layout_struct_packed/output.json create mode 100644 test/cmdlineTests/storage_layout_value_types/input.json create mode 100644 test/cmdlineTests/storage_layout_value_types/output.json create mode 100644 test/cmdlineTests/storage_layout_value_types_packed/input.json create mode 100644 test/cmdlineTests/storage_layout_value_types_packed/output.json diff --git a/Changelog.md b/Changelog.md index 0278176b5..d3294901f 100644 --- a/Changelog.md +++ b/Changelog.md @@ -10,6 +10,7 @@ Compiler Features: * SMTChecker: Add break/continue support to the CHC engine. * SMTChecker: Support assignments to multi-dimensional arrays and mappings. * SMTChecker: Support inheritance and function overriding. + * Standard JSON Interface: Output the storage layout of a contract when artifact ``storageLayout`` is requested. * TypeChecker: List possible candidates when overload resolution fails. diff --git a/docs/miscellaneous.rst b/docs/miscellaneous.rst index 137513b83..74c2d0326 100644 --- a/docs/miscellaneous.rst +++ b/docs/miscellaneous.rst @@ -8,6 +8,8 @@ Miscellaneous Layout of State Variables in Storage ************************************ +.. _storage-inplace-encoding: + Statically-sized variables (everything except mapping and dynamically-sized array types) are laid out contiguously in storage starting from position ``0``. Multiple, contiguous items that need less than 32 bytes are packed into a single storage slot if possible, according to the following rules: - The first item in a storage slot is stored lower-order aligned. @@ -49,6 +51,8 @@ The elements of structs and arrays are stored after each other, just as if they Mappings and Dynamic Arrays =========================== +.. _storage-hashed-encoding: + Due to their unpredictable size, mapping and dynamically-sized array types use a Keccak-256 hash computation to find the starting position of the value or the array data. These starting positions are always full stack slots. @@ -88,6 +92,267 @@ by checking if the lowest bit is set: short (not set) and long (set). .. note:: Handling invalidly encoded slots is currently not supported but may be added in the future. +JSON Output +=========== + +.. _storage-layout-top-level: + +The storage layout of a contract can be requested via the :ref:`standard JSON interface `. The output is a JSON object containing two keys, +``storage`` and ``types``. The ``storage`` object is an array where each +element has the following form: + + +.. code:: + + + { + "astId": 2, + "contract": "fileA:A", + "label": "x", + "offset": 0, + "slot": "0", + "type": "t_uint256" + } + +where the example above is the storage layout of ``contract A { uint x; }`` from source unit ``fileA`` +and + +- ``astId`` is the id of the AST node of the state variable's declaration +- ``contract`` is the name of the contract including its path as prefix +- ``label`` is the name of the state variable +- ``offset`` is the offset in bytes within the storage slot according to the encoding +- ``slot`` is the storage slot where the state variable resides or starts. This + number may be very large and therefore its JSON value is represented as a + string. +- ``type`` is an identifier used as key to the variable's type information (described in the following) + +The given ``type``, in this case ``t_uint256`` represents an element in +``types``, which has the form: + + +.. code:: + + { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32", + } + +where + +- ``encoding`` how the data is encoded in storage, where the possible values are: + + - ``inplace``: data is laid out contiguously in storage (see :ref:`above `). + - ``mapping``: Keccak-256 hash-based method (see :ref:`above `). + - ``dynamic_array``: Keccak-256 hash-based method (see :ref:`above `). + - ``bytes``: single slot or Keccak-256 hash-based depending on the data size (see :ref:`above `). + +- ``label`` is the canonical type name. +- ``numberOfBytes`` is the number of used bytes (as a decimal string). Note that if ``numberOfBytes > 32`` this means that more than one slot is used. + +Some types have extra information besides the four above. Mappings contain +its ``key`` and ``value`` types (again referencing an entry in this mapping +of types), arrays have its ``base`` type, and structs list their ``members`` in +the same format as the top-level ``storage`` (see :ref:`above +`). + +.. note :: + The JSON output format of a contract's storage layout is still considered experimental + and is subject to change in non-breaking releases of Solidity. + +The following example shows a contract and its storage layout, containing +value and reference types, types that are encoded packed, and nested types. + + +.. code:: + + pragma solidity >=0.4.0 <0.7.0; + contract A { + struct S { + uint128 a; + uint128 b; + uint[2] staticArray; + uint[] dynArray; + } + + uint x; + uint y; + S s; + address addr; + mapping (uint => mapping (address => bool)) map; + uint[] array; + string s1; + bytes b1; + } + +.. code:: + + "storageLayout": { + "storage": [ + { + "astId": 14, + "contract": "fileA:A", + "label": "x", + "offset": 0, + "slot": "0", + "type": "t_uint256" + }, + { + "astId": 16, + "contract": "fileA:A", + "label": "y", + "offset": 0, + "slot": "1", + "type": "t_uint256" + }, + { + "astId": 18, + "contract": "fileA:A", + "label": "s", + "offset": 0, + "slot": "2", + "type": "t_struct(S)12_storage" + }, + { + "astId": 20, + "contract": "fileA:A", + "label": "addr", + "offset": 0, + "slot": "6", + "type": "t_address" + }, + { + "astId": 26, + "contract": "fileA:A", + "label": "map", + "offset": 0, + "slot": "7", + "type": "t_mapping(t_uint256,t_mapping(t_address,t_bool))" + }, + { + "astId": 29, + "contract": "fileA:A", + "label": "array", + "offset": 0, + "slot": "8", + "type": "t_array(t_uint256)dyn_storage" + }, + { + "astId": 31, + "contract": "fileA:A", + "label": "s1", + "offset": 0, + "slot": "9", + "type": "t_string_storage" + }, + { + "astId": 33, + "contract": "fileA:A", + "label": "b1", + "offset": 0, + "slot": "10", + "type": "t_bytes_storage" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_uint256)2_storage": { + "base": "t_uint256", + "encoding": "inplace", + "label": "uint256[2]", + "numberOfBytes": "64" + }, + "t_array(t_uint256)dyn_storage": { + "base": "t_uint256", + "encoding": "dynamic_array", + "label": "uint256[]", + "numberOfBytes": "32" + }, + "t_bool": { + "encoding": "inplace", + "label": "bool", + "numberOfBytes": "1" + }, + "t_bytes_storage": { + "encoding": "bytes", + "label": "bytes", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_bool)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => bool)", + "numberOfBytes": "32", + "value": "t_bool" + }, + "t_mapping(t_uint256,t_mapping(t_address,t_bool))": { + "encoding": "mapping", + "key": "t_uint256", + "label": "mapping(uint256 => mapping(address => bool))", + "numberOfBytes": "32", + "value": "t_mapping(t_address,t_bool)" + }, + "t_string_storage": { + "encoding": "bytes", + "label": "string", + "numberOfBytes": "32" + }, + "t_struct(S)12_storage": { + "encoding": "inplace", + "label": "struct A.S", + "members": [ + { + "astId": 2, + "contract": "fileA:A", + "label": "a", + "offset": 0, + "slot": "0", + "type": "t_uint128" + }, + { + "astId": 4, + "contract": "fileA:A", + "label": "b", + "offset": 16, + "slot": "0", + "type": "t_uint128" + }, + { + "astId": 8, + "contract": "fileA:A", + "label": "staticArray", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)2_storage" + }, + { + "astId": 11, + "contract": "fileA:A", + "label": "dynArray", + "offset": 0, + "slot": "3", + "type": "t_array(t_uint256)dyn_storage" + } + ], + "numberOfBytes": "128" + }, + "t_uint128": { + "encoding": "inplace", + "label": "uint128", + "numberOfBytes": "16" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + } + } + } + .. index: memory layout **************** diff --git a/docs/using-the-compiler.rst b/docs/using-the-compiler.rst index 12df74e84..db09b2a09 100644 --- a/docs/using-the-compiler.rst +++ b/docs/using-the-compiler.rst @@ -276,6 +276,7 @@ Input Description // metadata - Metadata // ir - Yul intermediate representation of the code before optimization // irOptimized - Intermediate representation after optimization + // storageLayout - Slots, offsets and types of the contract's state variables. // evm.assembly - New assembly format // evm.legacyAssembly - Old-style assembly format in JSON // evm.bytecode.object - Bytecode object @@ -376,6 +377,8 @@ Output Description "devdoc": {}, // Intermediate representation (string) "ir": "", + // See the Storage Layout documentation. + "storageLayout": {"storage": [...], "types": {...} }, // EVM-related outputs "evm": { // Assembly (string) diff --git a/libsolidity/CMakeLists.txt b/libsolidity/CMakeLists.txt index 714c3c766..ded239559 100644 --- a/libsolidity/CMakeLists.txt +++ b/libsolidity/CMakeLists.txt @@ -113,6 +113,8 @@ set(sources interface/ReadFile.h interface/StandardCompiler.cpp interface/StandardCompiler.h + interface/StorageLayout.cpp + interface/StorageLayout.h interface/Version.cpp interface/Version.h parsing/DocStringParser.cpp diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index fa7c9ec95..9f941cf52 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -667,6 +668,28 @@ Json::Value const& CompilerStack::contractABI(Contract const& _contract) const return *_contract.abi; } +Json::Value const& CompilerStack::storageLayout(string const& _contractName) const +{ + if (m_stackState < AnalysisPerformed) + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Analysis was not successful.")); + + return storageLayout(contract(_contractName)); +} + +Json::Value const& CompilerStack::storageLayout(Contract const& _contract) const +{ + if (m_stackState < AnalysisPerformed) + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Analysis was not successful.")); + + solAssert(_contract.contract, ""); + + // caches the result + if (!_contract.storageLayout) + _contract.storageLayout.reset(new Json::Value(StorageLayout().generate(*_contract.contract))); + + return *_contract.storageLayout; +} + Json::Value const& CompilerStack::natspecUser(string const& _contractName) const { if (m_stackState < AnalysisPerformed) diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h index 43d04cedb..005ef911f 100644 --- a/libsolidity/interface/CompilerStack.h +++ b/libsolidity/interface/CompilerStack.h @@ -272,6 +272,10 @@ public: /// Prerequisite: Successful call to parse or compile. Json::Value const& contractABI(std::string const& _contractName) const; + /// @returns a JSON representing the storage layout of the contract. + /// Prerequisite: Successful call to parse or compile. + Json::Value const& storageLayout(std::string const& _contractName) const; + /// @returns a JSON representing the contract's user documentation. /// Prerequisite: Successful call to parse or compile. Json::Value const& natspecUser(std::string const& _contractName) const; @@ -319,6 +323,7 @@ private: eth::LinkerObject eWasmObject; ///< Experimental eWasm code mutable std::unique_ptr metadata; ///< The metadata json that will be hashed into the chain. mutable std::unique_ptr abi; + mutable std::unique_ptr storageLayout; mutable std::unique_ptr userDocumentation; mutable std::unique_ptr devDocumentation; mutable std::unique_ptr sourceMapping; @@ -382,6 +387,10 @@ private: /// This will generate the JSON object and store it in the Contract object if it is not present yet. Json::Value const& contractABI(Contract const&) const; + /// @returns the storage layout of the contract as a JSON object. + /// This will generate the JSON object and store it in the Contract object if it is not present yet. + Json::Value const& storageLayout(Contract const&) const; + /// @returns the Natspec User documentation as a JSON object. /// This will generate the JSON object and store it in the Contract object if it is not present yet. Json::Value const& natspecUser(Contract const&) const; diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index d1701320f..921e90231 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -887,10 +887,12 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting string file = contractName.substr(0, colon); string name = contractName.substr(colon + 1); - // ABI, documentation and metadata + // ABI, storage layout, documentation and metadata Json::Value contractData(Json::objectValue); if (isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "abi", wildcardMatchesExperimental)) contractData["abi"] = compilerStack.contractABI(contractName); + if (isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "storageLayout", false)) + contractData["storageLayout"] = compilerStack.storageLayout(contractName); if (isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "metadata", wildcardMatchesExperimental)) contractData["metadata"] = compilerStack.metadata(contractName); if (isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "userdoc", wildcardMatchesExperimental)) diff --git a/libsolidity/interface/StorageLayout.cpp b/libsolidity/interface/StorageLayout.cpp new file mode 100644 index 000000000..e987d4de2 --- /dev/null +++ b/libsolidity/interface/StorageLayout.cpp @@ -0,0 +1,119 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ + +#include + +#include + +using namespace std; +using namespace dev; +using namespace dev::solidity; + +Json::Value StorageLayout::generate(ContractDefinition const& _contractDef) +{ + solAssert(!m_contract, ""); + m_contract = &_contractDef; + m_types.clear(); + + auto typeType = dynamic_cast(_contractDef.type()); + solAssert(typeType, ""); + auto contractType = dynamic_cast(typeType->actualType()); + solAssert(contractType, ""); + + Json::Value variables(Json::arrayValue); + for (auto [var, slot, offset]: contractType->stateVariables()) + variables.append(generate(*var, slot, offset)); + + Json::Value layout; + layout["storage"] = move(variables); + layout["types"] = move(m_types); + return layout; +} + +Json::Value StorageLayout::generate(VariableDeclaration const& _var, u256 const& _slot, unsigned _offset) +{ + Json::Value varEntry; + TypePointer varType = _var.type(); + + varEntry["label"] = _var.name(); + varEntry["astId"] = int(_var.id()); + varEntry["contract"] = m_contract->fullyQualifiedName(); + varEntry["slot"] = _slot.str(); + varEntry["offset"] = _offset; + varEntry["type"] = typeKeyName(varType); + + generate(varType); + + return varEntry; +} + +void StorageLayout::generate(TypePointer _type) +{ + if (m_types.isMember(typeKeyName(_type))) + return; + + // Register it now to cut recursive visits. + Json::Value& typeInfo = m_types[typeKeyName(_type)]; + typeInfo["label"] = _type->toString(true); + typeInfo["numberOfBytes"] = u256(_type->storageBytes() * _type->storageSize()).str(); + + if (auto structType = dynamic_cast(_type)) + { + Json::Value members(Json::arrayValue); + auto const& structDef = structType->structDefinition(); + for (auto const& member: structDef.members()) + { + auto const& offsets = structType->storageOffsetsOfMember(member->name()); + members.append(generate(*member, offsets.first, offsets.second)); + } + typeInfo["members"] = move(members); + typeInfo["encoding"] = "inplace"; + } + else if (auto mappingType = dynamic_cast(_type)) + { + typeInfo["key"] = typeKeyName(mappingType->keyType()); + typeInfo["value"] = typeKeyName(mappingType->valueType()); + generate(mappingType->keyType()); + generate(mappingType->valueType()); + typeInfo["encoding"] = "mapping"; + } + else if (auto arrayType = dynamic_cast(_type)) + { + if (arrayType->isByteArray()) + typeInfo["encoding"] = "bytes"; + else + { + typeInfo["base"] = typeKeyName(arrayType->baseType()); + generate(arrayType->baseType()); + typeInfo["encoding"] = arrayType->isDynamicallySized() ? "dynamic_array" : "inplace"; + } + } + else + { + solAssert(_type->isValueType(), ""); + typeInfo["encoding"] = "inplace"; + } + + solAssert(typeInfo.isMember("encoding"), ""); +} + +string StorageLayout::typeKeyName(TypePointer _type) +{ + if (auto refType = dynamic_cast(_type)) + return TypeProvider::withLocationIfReference(refType->location(), _type)->richIdentifier(); + return _type->richIdentifier(); +} diff --git a/libsolidity/interface/StorageLayout.h b/libsolidity/interface/StorageLayout.h new file mode 100644 index 000000000..1f7b3c1fd --- /dev/null +++ b/libsolidity/interface/StorageLayout.h @@ -0,0 +1,58 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +/** + * Generates the storage layout of a contract. + */ + +#pragma once + +#include +#include + +#include + +namespace dev +{ +namespace solidity +{ + +class StorageLayout +{ +public: + /// Generates the storage layout of the contract + /// @param _contractDef The contract definition + /// @return A JSON representation of the contract's storage layout. + Json::Value generate(ContractDefinition const& _contractDef); + +private: + /// Generates the JSON information for a variable and its storage location. + Json::Value generate(VariableDeclaration const& _var, u256 const& _slot, unsigned _offset); + + /// Generates the JSON information for @param _type + void generate(TypePointer _type); + + /// The key for the JSON object describing a type. + std::string typeKeyName(TypePointer _type); + + Json::Value m_types; + + /// Current analyzed contract + ContractDefinition const* m_contract = nullptr; +}; + +} +} diff --git a/test/cmdlineTests/storage_layout_bytes/input.json b/test/cmdlineTests/storage_layout_bytes/input.json new file mode 100644 index 000000000..fe1468c53 --- /dev/null +++ b/test/cmdlineTests/storage_layout_bytes/input.json @@ -0,0 +1,16 @@ +{ + "language": "Solidity", + "sources": { + "fileA": { + "content": "contract A { bytes s1 = \"test\"; bytes s2; }" + } + }, + "settings": { + "outputSelection": { + "fileA": { + "A": [ "storageLayout" ], + "": [ "storageLayout" ] + } + } + } +} diff --git a/test/cmdlineTests/storage_layout_bytes/output.json b/test/cmdlineTests/storage_layout_bytes/output.json new file mode 100644 index 000000000..d2829f360 --- /dev/null +++ b/test/cmdlineTests/storage_layout_bytes/output.json @@ -0,0 +1,4 @@ +{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":3,"contract":"fileA:A","label":"s1","offset":0,"slot":"0","type":"t_bytes_storage"},{"astId":5,"contract":"fileA:A","label":"s2","offset":0,"slot":"1","type":"t_bytes_storage"}],"types":{"t_bytes_storage":{"encoding":"bytes","label":"bytes","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA:1:1: Warning: Source file does not specify required compiler version! +contract A { bytes s1 = \"test\"; bytes s2; } +^-----------------------------------------^ +","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":43,"file":"fileA","start":0},"type":"Warning"}],"sources":{"fileA":{"id":0}}} diff --git a/test/cmdlineTests/storage_layout_dyn_array/input.json b/test/cmdlineTests/storage_layout_dyn_array/input.json new file mode 100644 index 000000000..64ab3e20b --- /dev/null +++ b/test/cmdlineTests/storage_layout_dyn_array/input.json @@ -0,0 +1,16 @@ +{ + "language": "Solidity", + "sources": { + "fileA": { + "content": "contract A { uint[] array1; bool[] array2; }" + } + }, + "settings": { + "outputSelection": { + "fileA": { + "A": [ "storageLayout" ], + "": [ "storageLayout" ] + } + } + } +} diff --git a/test/cmdlineTests/storage_layout_dyn_array/output.json b/test/cmdlineTests/storage_layout_dyn_array/output.json new file mode 100644 index 000000000..51b3ac1a1 --- /dev/null +++ b/test/cmdlineTests/storage_layout_dyn_array/output.json @@ -0,0 +1,4 @@ +{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":3,"contract":"fileA:A","label":"array1","offset":0,"slot":"0","type":"t_array(t_uint256)dyn_storage"},{"astId":6,"contract":"fileA:A","label":"array2","offset":0,"slot":"1","type":"t_array(t_bool)dyn_storage"}],"types":{"t_array(t_bool)dyn_storage":{"base":"t_bool","encoding":"dynamic_array","label":"bool[]","numberOfBytes":"32"},"t_array(t_uint256)dyn_storage":{"base":"t_uint256","encoding":"dynamic_array","label":"uint256[]","numberOfBytes":"32"},"t_bool":{"encoding":"inplace","label":"bool","numberOfBytes":"1"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA:1:1: Warning: Source file does not specify required compiler version! +contract A { uint[] array1; bool[] array2; } +^------------------------------------------^ +","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":44,"file":"fileA","start":0},"type":"Warning"}],"sources":{"fileA":{"id":0}}} diff --git a/test/cmdlineTests/storage_layout_many/input.json b/test/cmdlineTests/storage_layout_many/input.json new file mode 100644 index 000000000..7ea41f211 --- /dev/null +++ b/test/cmdlineTests/storage_layout_many/input.json @@ -0,0 +1,16 @@ +{ + "language": "Solidity", + "sources": { + "fileA": { + "content": "contract A { struct S { uint128 a; uint128 b; uint[2] staticArray; uint[] dynArray; } uint x; uint y; S s; address addr; mapping (uint => mapping (address => bool)) map; uint[] array; string s1; bytes b1; }" + } + }, + "settings": { + "outputSelection": { + "fileA": { + "A": [ "storageLayout" ], + "": [ "storageLayout" ] + } + } + } +} diff --git a/test/cmdlineTests/storage_layout_many/output.json b/test/cmdlineTests/storage_layout_many/output.json new file mode 100644 index 000000000..a2b3f8d2d --- /dev/null +++ b/test/cmdlineTests/storage_layout_many/output.json @@ -0,0 +1,4 @@ +{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":14,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":16,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":18,"contract":"fileA:A","label":"s","offset":0,"slot":"2","type":"t_struct(S)12_storage"},{"astId":20,"contract":"fileA:A","label":"addr","offset":0,"slot":"6","type":"t_address"},{"astId":26,"contract":"fileA:A","label":"map","offset":0,"slot":"7","type":"t_mapping(t_uint256,t_mapping(t_address,t_bool))"},{"astId":29,"contract":"fileA:A","label":"array","offset":0,"slot":"8","type":"t_array(t_uint256)dyn_storage"},{"astId":31,"contract":"fileA:A","label":"s1","offset":0,"slot":"9","type":"t_string_storage"},{"astId":33,"contract":"fileA:A","label":"b1","offset":0,"slot":"10","type":"t_bytes_storage"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_array(t_uint256)2_storage":{"base":"t_uint256","encoding":"inplace","label":"uint256[2]","numberOfBytes":"64"},"t_array(t_uint256)dyn_storage":{"base":"t_uint256","encoding":"dynamic_array","label":"uint256[]","numberOfBytes":"32"},"t_bool":{"encoding":"inplace","label":"bool","numberOfBytes":"1"},"t_bytes_storage":{"encoding":"bytes","label":"bytes","numberOfBytes":"32"},"t_mapping(t_address,t_bool)":{"encoding":"mapping","key":"t_address","label":"mapping(address => bool)","numberOfBytes":"32","value":"t_bool"},"t_mapping(t_uint256,t_mapping(t_address,t_bool))":{"encoding":"mapping","key":"t_uint256","label":"mapping(uint256 => mapping(address => bool))","numberOfBytes":"32","value":"t_mapping(t_address,t_bool)"},"t_string_storage":{"encoding":"bytes","label":"string","numberOfBytes":"32"},"t_struct(S)12_storage":{"encoding":"inplace","label":"struct A.S","members":[{"astId":2,"contract":"fileA:A","label":"a","offset":0,"slot":"0","type":"t_uint128"},{"astId":4,"contract":"fileA:A","label":"b","offset":16,"slot":"0","type":"t_uint128"},{"astId":8,"contract":"fileA:A","label":"staticArray","offset":0,"slot":"1","type":"t_array(t_uint256)2_storage"},{"astId":11,"contract":"fileA:A","label":"dynArray","offset":0,"slot":"3","type":"t_array(t_uint256)dyn_storage"}],"numberOfBytes":"128"},"t_uint128":{"encoding":"inplace","label":"uint128","numberOfBytes":"16"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA:1:1: Warning: Source file does not specify required compiler version! +contract A { struct S { uint128 a; ... int[] array; string s1; bytes b1; } +^-------------------------------------------------------------------------^ +","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":206,"file":"fileA","start":0},"type":"Warning"}],"sources":{"fileA":{"id":0}}} diff --git a/test/cmdlineTests/storage_layout_mapping/input.json b/test/cmdlineTests/storage_layout_mapping/input.json new file mode 100644 index 000000000..6292391d5 --- /dev/null +++ b/test/cmdlineTests/storage_layout_mapping/input.json @@ -0,0 +1,16 @@ +{ + "language": "Solidity", + "sources": { + "fileA": { + "content": "contract A { uint x; uint y; mapping (uint => mapping (address => bool)) map; }" + } + }, + "settings": { + "outputSelection": { + "fileA": { + "A": [ "storageLayout" ], + "": [ "storageLayout" ] + } + } + } +} diff --git a/test/cmdlineTests/storage_layout_mapping/output.json b/test/cmdlineTests/storage_layout_mapping/output.json new file mode 100644 index 000000000..4696d46c8 --- /dev/null +++ b/test/cmdlineTests/storage_layout_mapping/output.json @@ -0,0 +1,4 @@ +{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":2,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":4,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":10,"contract":"fileA:A","label":"map","offset":0,"slot":"2","type":"t_mapping(t_uint256,t_mapping(t_address,t_bool))"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_bool":{"encoding":"inplace","label":"bool","numberOfBytes":"1"},"t_mapping(t_address,t_bool)":{"encoding":"mapping","key":"t_address","label":"mapping(address => bool)","numberOfBytes":"32","value":"t_bool"},"t_mapping(t_uint256,t_mapping(t_address,t_bool))":{"encoding":"mapping","key":"t_uint256","label":"mapping(uint256 => mapping(address => bool))","numberOfBytes":"32","value":"t_mapping(t_address,t_bool)"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA:1:1: Warning: Source file does not specify required compiler version! +contract A { uint x; uint y; mapping (uint => mapping (address => bool)) map; } +^-----------------------------------------------------------------------------^ +","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":79,"file":"fileA","start":0},"type":"Warning"}],"sources":{"fileA":{"id":0}}} diff --git a/test/cmdlineTests/storage_layout_smoke/input.json b/test/cmdlineTests/storage_layout_smoke/input.json new file mode 100644 index 000000000..47722e759 --- /dev/null +++ b/test/cmdlineTests/storage_layout_smoke/input.json @@ -0,0 +1,16 @@ +{ + "language": "Solidity", + "sources": { + "fileA": { + "content": "contract A { }" + } + }, + "settings": { + "outputSelection": { + "fileA": { + "A": [ "storageLayout" ], + "": [ "storageLayout" ] + } + } + } +} diff --git a/test/cmdlineTests/storage_layout_smoke/output.json b/test/cmdlineTests/storage_layout_smoke/output.json new file mode 100644 index 000000000..08191bc5d --- /dev/null +++ b/test/cmdlineTests/storage_layout_smoke/output.json @@ -0,0 +1,4 @@ +{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[],"types":null}}}},"errors":[{"component":"general","formattedMessage":"fileA:1:1: Warning: Source file does not specify required compiler version! +contract A { } +^------------^ +","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":14,"file":"fileA","start":0},"type":"Warning"}],"sources":{"fileA":{"id":0}}} diff --git a/test/cmdlineTests/storage_layout_smoke_two_contracts/input.json b/test/cmdlineTests/storage_layout_smoke_two_contracts/input.json new file mode 100644 index 000000000..b31f3dd9d --- /dev/null +++ b/test/cmdlineTests/storage_layout_smoke_two_contracts/input.json @@ -0,0 +1,19 @@ +{ + "language": "Solidity", + "sources": { + "fileA": { + "content": "contract A { }" + }, + "fileB": { + "content": "contract A { uint x; uint y; }" + } + }, + "settings": { + "outputSelection": { + "fileA": { + "A": [ "storageLayout" ], + "": [ "storageLayout" ] + } + } + } +} diff --git a/test/cmdlineTests/storage_layout_smoke_two_contracts/output.json b/test/cmdlineTests/storage_layout_smoke_two_contracts/output.json new file mode 100644 index 000000000..761cf8334 --- /dev/null +++ b/test/cmdlineTests/storage_layout_smoke_two_contracts/output.json @@ -0,0 +1,4 @@ +{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[],"types":null}}}},"errors":[{"component":"general","formattedMessage":"fileA:1:1: Warning: Source file does not specify required compiler version! +contract A { } +^------------^ +","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":14,"file":"fileA","start":0},"type":"Warning"}],"sources":{"fileA":{"id":0},"fileB":{"id":1}}} diff --git a/test/cmdlineTests/storage_layout_string/input.json b/test/cmdlineTests/storage_layout_string/input.json new file mode 100644 index 000000000..834617b3a --- /dev/null +++ b/test/cmdlineTests/storage_layout_string/input.json @@ -0,0 +1,16 @@ +{ + "language": "Solidity", + "sources": { + "fileA": { + "content": "contract A { string s1 = \"test\"; string s2; }" + } + }, + "settings": { + "outputSelection": { + "fileA": { + "A": [ "storageLayout" ], + "": [ "storageLayout" ] + } + } + } +} diff --git a/test/cmdlineTests/storage_layout_string/output.json b/test/cmdlineTests/storage_layout_string/output.json new file mode 100644 index 000000000..19066171e --- /dev/null +++ b/test/cmdlineTests/storage_layout_string/output.json @@ -0,0 +1,4 @@ +{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":3,"contract":"fileA:A","label":"s1","offset":0,"slot":"0","type":"t_string_storage"},{"astId":5,"contract":"fileA:A","label":"s2","offset":0,"slot":"1","type":"t_string_storage"}],"types":{"t_string_storage":{"encoding":"bytes","label":"string","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA:1:1: Warning: Source file does not specify required compiler version! +contract A { string s1 = \"test\"; string s2; } +^-------------------------------------------^ +","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":45,"file":"fileA","start":0},"type":"Warning"}],"sources":{"fileA":{"id":0}}} diff --git a/test/cmdlineTests/storage_layout_struct/input.json b/test/cmdlineTests/storage_layout_struct/input.json new file mode 100644 index 000000000..31ab020cf --- /dev/null +++ b/test/cmdlineTests/storage_layout_struct/input.json @@ -0,0 +1,16 @@ +{ + "language": "Solidity", + "sources": { + "fileA": { + "content": "contract A { struct S { uint a; uint b; uint[2] staticArray; uint[] dynArray; } uint x; uint y; S s; address addr; }" + } + }, + "settings": { + "outputSelection": { + "fileA": { + "A": [ "storageLayout" ], + "": [ "storageLayout" ] + } + } + } +} diff --git a/test/cmdlineTests/storage_layout_struct/output.json b/test/cmdlineTests/storage_layout_struct/output.json new file mode 100644 index 000000000..a925c99c0 --- /dev/null +++ b/test/cmdlineTests/storage_layout_struct/output.json @@ -0,0 +1,4 @@ +{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":14,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":16,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":18,"contract":"fileA:A","label":"s","offset":0,"slot":"2","type":"t_struct(S)12_storage"},{"astId":20,"contract":"fileA:A","label":"addr","offset":0,"slot":"7","type":"t_address"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_array(t_uint256)2_storage":{"base":"t_uint256","encoding":"inplace","label":"uint256[2]","numberOfBytes":"64"},"t_array(t_uint256)dyn_storage":{"base":"t_uint256","encoding":"dynamic_array","label":"uint256[]","numberOfBytes":"32"},"t_struct(S)12_storage":{"encoding":"inplace","label":"struct A.S","members":[{"astId":2,"contract":"fileA:A","label":"a","offset":0,"slot":"0","type":"t_uint256"},{"astId":4,"contract":"fileA:A","label":"b","offset":0,"slot":"1","type":"t_uint256"},{"astId":8,"contract":"fileA:A","label":"staticArray","offset":0,"slot":"2","type":"t_array(t_uint256)2_storage"},{"astId":11,"contract":"fileA:A","label":"dynArray","offset":0,"slot":"4","type":"t_array(t_uint256)dyn_storage"}],"numberOfBytes":"160"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA:1:1: Warning: Source file does not specify required compiler version! +contract A { struct S { uint a; uint b; uint[2] staticArray; uint[] dynArray; } uint x; uint y; S s; address addr; } +^------------------------------------------------------------------------------------------------------------------^ +","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":116,"file":"fileA","start":0},"type":"Warning"}],"sources":{"fileA":{"id":0}}} diff --git a/test/cmdlineTests/storage_layout_struct_packed/input.json b/test/cmdlineTests/storage_layout_struct_packed/input.json new file mode 100644 index 000000000..80c706c7b --- /dev/null +++ b/test/cmdlineTests/storage_layout_struct_packed/input.json @@ -0,0 +1,16 @@ +{ + "language": "Solidity", + "sources": { + "fileA": { + "content": "contract A { struct S { uint128 a; uint128 b; uint[2] staticArray; uint[] dynArray; } uint x; uint y; S s; address addr; }" + } + }, + "settings": { + "outputSelection": { + "fileA": { + "A": [ "storageLayout" ], + "": [ "storageLayout" ] + } + } + } +} diff --git a/test/cmdlineTests/storage_layout_struct_packed/output.json b/test/cmdlineTests/storage_layout_struct_packed/output.json new file mode 100644 index 000000000..fe9bd0d50 --- /dev/null +++ b/test/cmdlineTests/storage_layout_struct_packed/output.json @@ -0,0 +1,4 @@ +{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":14,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":16,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":18,"contract":"fileA:A","label":"s","offset":0,"slot":"2","type":"t_struct(S)12_storage"},{"astId":20,"contract":"fileA:A","label":"addr","offset":0,"slot":"6","type":"t_address"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_array(t_uint256)2_storage":{"base":"t_uint256","encoding":"inplace","label":"uint256[2]","numberOfBytes":"64"},"t_array(t_uint256)dyn_storage":{"base":"t_uint256","encoding":"dynamic_array","label":"uint256[]","numberOfBytes":"32"},"t_struct(S)12_storage":{"encoding":"inplace","label":"struct A.S","members":[{"astId":2,"contract":"fileA:A","label":"a","offset":0,"slot":"0","type":"t_uint128"},{"astId":4,"contract":"fileA:A","label":"b","offset":16,"slot":"0","type":"t_uint128"},{"astId":8,"contract":"fileA:A","label":"staticArray","offset":0,"slot":"1","type":"t_array(t_uint256)2_storage"},{"astId":11,"contract":"fileA:A","label":"dynArray","offset":0,"slot":"3","type":"t_array(t_uint256)dyn_storage"}],"numberOfBytes":"128"},"t_uint128":{"encoding":"inplace","label":"uint128","numberOfBytes":"16"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA:1:1: Warning: Source file does not specify required compiler version! +contract A { struct S { uint128 a; uint128 b; uint[2] staticArray; uint[] dynArray; } uint x; uint y; S s; address addr; } +^------------------------------------------------------------------------------------------------------------------------^ +","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":122,"file":"fileA","start":0},"type":"Warning"}],"sources":{"fileA":{"id":0}}} diff --git a/test/cmdlineTests/storage_layout_value_types/input.json b/test/cmdlineTests/storage_layout_value_types/input.json new file mode 100644 index 000000000..1477dde08 --- /dev/null +++ b/test/cmdlineTests/storage_layout_value_types/input.json @@ -0,0 +1,16 @@ +{ + "language": "Solidity", + "sources": { + "fileA": { + "content": "contract A { uint x; uint y; address addr; uint[2] array; }" + } + }, + "settings": { + "outputSelection": { + "fileA": { + "A": [ "storageLayout" ], + "": [ "storageLayout" ] + } + } + } +} diff --git a/test/cmdlineTests/storage_layout_value_types/output.json b/test/cmdlineTests/storage_layout_value_types/output.json new file mode 100644 index 000000000..cb43276ed --- /dev/null +++ b/test/cmdlineTests/storage_layout_value_types/output.json @@ -0,0 +1,4 @@ +{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":2,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":4,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":6,"contract":"fileA:A","label":"addr","offset":0,"slot":"2","type":"t_address"},{"astId":10,"contract":"fileA:A","label":"array","offset":0,"slot":"3","type":"t_array(t_uint256)2_storage"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_array(t_uint256)2_storage":{"base":"t_uint256","encoding":"inplace","label":"uint256[2]","numberOfBytes":"64"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA:1:1: Warning: Source file does not specify required compiler version! +contract A { uint x; uint y; address addr; uint[2] array; } +^---------------------------------------------------------^ +","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":59,"file":"fileA","start":0},"type":"Warning"}],"sources":{"fileA":{"id":0}}} diff --git a/test/cmdlineTests/storage_layout_value_types_packed/input.json b/test/cmdlineTests/storage_layout_value_types_packed/input.json new file mode 100644 index 000000000..04a7bd3bf --- /dev/null +++ b/test/cmdlineTests/storage_layout_value_types_packed/input.json @@ -0,0 +1,16 @@ +{ + "language": "Solidity", + "sources": { + "fileA": { + "content": "contract A { uint64 x; uint128 y; uint128 z; address addr; uint[2] array; }" + } + }, + "settings": { + "outputSelection": { + "fileA": { + "A": [ "storageLayout" ], + "": [ "storageLayout" ] + } + } + } +} diff --git a/test/cmdlineTests/storage_layout_value_types_packed/output.json b/test/cmdlineTests/storage_layout_value_types_packed/output.json new file mode 100644 index 000000000..cd7f866aa --- /dev/null +++ b/test/cmdlineTests/storage_layout_value_types_packed/output.json @@ -0,0 +1,4 @@ +{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":2,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint64"},{"astId":4,"contract":"fileA:A","label":"y","offset":8,"slot":"0","type":"t_uint128"},{"astId":6,"contract":"fileA:A","label":"z","offset":0,"slot":"1","type":"t_uint128"},{"astId":8,"contract":"fileA:A","label":"addr","offset":0,"slot":"2","type":"t_address"},{"astId":12,"contract":"fileA:A","label":"array","offset":0,"slot":"3","type":"t_array(t_uint256)2_storage"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_array(t_uint256)2_storage":{"base":"t_uint256","encoding":"inplace","label":"uint256[2]","numberOfBytes":"64"},"t_uint128":{"encoding":"inplace","label":"uint128","numberOfBytes":"16"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"},"t_uint64":{"encoding":"inplace","label":"uint64","numberOfBytes":"8"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA:1:1: Warning: Source file does not specify required compiler version! +contract A { uint64 x; uint128 y; uint128 z; address addr; uint[2] array; } +^-------------------------------------------------------------------------^ +","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":75,"file":"fileA","start":0},"type":"Warning"}],"sources":{"fileA":{"id":0}}}