mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #7589 from ethereum/storage_layout
Output the storage layout of a contract via storageLayout artifact
This commit is contained in:
commit
d1c6ab8abe
@ -10,6 +10,7 @@ Compiler Features:
|
|||||||
* SMTChecker: Add break/continue support to the CHC engine.
|
* SMTChecker: Add break/continue support to the CHC engine.
|
||||||
* SMTChecker: Support assignments to multi-dimensional arrays and mappings.
|
* SMTChecker: Support assignments to multi-dimensional arrays and mappings.
|
||||||
* SMTChecker: Support inheritance and function overriding.
|
* 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.
|
* TypeChecker: List possible candidates when overload resolution fails.
|
||||||
|
|
||||||
|
|
||||||
|
@ -8,6 +8,8 @@ Miscellaneous
|
|||||||
Layout of State Variables in Storage
|
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:
|
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.
|
- 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
|
Mappings and Dynamic Arrays
|
||||||
===========================
|
===========================
|
||||||
|
|
||||||
|
.. _storage-hashed-encoding:
|
||||||
|
|
||||||
Due to their unpredictable size, mapping and dynamically-sized array types use a Keccak-256 hash
|
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.
|
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::
|
.. note::
|
||||||
Handling invalidly encoded slots is currently not supported but may be added in the future.
|
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 <compiler-api>`. 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 <storage-inplace-encoding>`).
|
||||||
|
- ``mapping``: Keccak-256 hash-based method (see :ref:`above <storage-hashed-encoding>`).
|
||||||
|
- ``dynamic_array``: Keccak-256 hash-based method (see :ref:`above <storage-hashed-encoding>`).
|
||||||
|
- ``bytes``: single slot or Keccak-256 hash-based depending on the data size (see :ref:`above <bytes-and-string>`).
|
||||||
|
|
||||||
|
- ``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
|
||||||
|
<storage-layout-top-level>`).
|
||||||
|
|
||||||
|
.. 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
|
.. index: memory layout
|
||||||
|
|
||||||
****************
|
****************
|
||||||
|
@ -276,6 +276,7 @@ Input Description
|
|||||||
// metadata - Metadata
|
// metadata - Metadata
|
||||||
// ir - Yul intermediate representation of the code before optimization
|
// ir - Yul intermediate representation of the code before optimization
|
||||||
// irOptimized - Intermediate representation after optimization
|
// irOptimized - Intermediate representation after optimization
|
||||||
|
// storageLayout - Slots, offsets and types of the contract's state variables.
|
||||||
// evm.assembly - New assembly format
|
// evm.assembly - New assembly format
|
||||||
// evm.legacyAssembly - Old-style assembly format in JSON
|
// evm.legacyAssembly - Old-style assembly format in JSON
|
||||||
// evm.bytecode.object - Bytecode object
|
// evm.bytecode.object - Bytecode object
|
||||||
@ -376,6 +377,8 @@ Output Description
|
|||||||
"devdoc": {},
|
"devdoc": {},
|
||||||
// Intermediate representation (string)
|
// Intermediate representation (string)
|
||||||
"ir": "",
|
"ir": "",
|
||||||
|
// See the Storage Layout documentation.
|
||||||
|
"storageLayout": {"storage": [...], "types": {...} },
|
||||||
// EVM-related outputs
|
// EVM-related outputs
|
||||||
"evm": {
|
"evm": {
|
||||||
// Assembly (string)
|
// Assembly (string)
|
||||||
|
@ -113,6 +113,8 @@ set(sources
|
|||||||
interface/ReadFile.h
|
interface/ReadFile.h
|
||||||
interface/StandardCompiler.cpp
|
interface/StandardCompiler.cpp
|
||||||
interface/StandardCompiler.h
|
interface/StandardCompiler.h
|
||||||
|
interface/StorageLayout.cpp
|
||||||
|
interface/StorageLayout.h
|
||||||
interface/Version.cpp
|
interface/Version.cpp
|
||||||
interface/Version.h
|
interface/Version.h
|
||||||
parsing/DocStringParser.cpp
|
parsing/DocStringParser.cpp
|
||||||
|
@ -43,6 +43,7 @@
|
|||||||
#include <libsolidity/interface/ABI.h>
|
#include <libsolidity/interface/ABI.h>
|
||||||
#include <libsolidity/interface/Natspec.h>
|
#include <libsolidity/interface/Natspec.h>
|
||||||
#include <libsolidity/interface/GasEstimator.h>
|
#include <libsolidity/interface/GasEstimator.h>
|
||||||
|
#include <libsolidity/interface/StorageLayout.h>
|
||||||
#include <libsolidity/interface/Version.h>
|
#include <libsolidity/interface/Version.h>
|
||||||
#include <libsolidity/parsing/Parser.h>
|
#include <libsolidity/parsing/Parser.h>
|
||||||
|
|
||||||
@ -667,6 +668,28 @@ Json::Value const& CompilerStack::contractABI(Contract const& _contract) const
|
|||||||
return *_contract.abi;
|
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
|
Json::Value const& CompilerStack::natspecUser(string const& _contractName) const
|
||||||
{
|
{
|
||||||
if (m_stackState < AnalysisPerformed)
|
if (m_stackState < AnalysisPerformed)
|
||||||
|
@ -272,6 +272,10 @@ public:
|
|||||||
/// Prerequisite: Successful call to parse or compile.
|
/// Prerequisite: Successful call to parse or compile.
|
||||||
Json::Value const& contractABI(std::string const& _contractName) const;
|
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.
|
/// @returns a JSON representing the contract's user documentation.
|
||||||
/// Prerequisite: Successful call to parse or compile.
|
/// Prerequisite: Successful call to parse or compile.
|
||||||
Json::Value const& natspecUser(std::string const& _contractName) const;
|
Json::Value const& natspecUser(std::string const& _contractName) const;
|
||||||
@ -319,6 +323,7 @@ private:
|
|||||||
eth::LinkerObject eWasmObject; ///< Experimental eWasm code
|
eth::LinkerObject eWasmObject; ///< Experimental eWasm code
|
||||||
mutable std::unique_ptr<std::string const> metadata; ///< The metadata json that will be hashed into the chain.
|
mutable std::unique_ptr<std::string const> metadata; ///< The metadata json that will be hashed into the chain.
|
||||||
mutable std::unique_ptr<Json::Value const> abi;
|
mutable std::unique_ptr<Json::Value const> abi;
|
||||||
|
mutable std::unique_ptr<Json::Value const> storageLayout;
|
||||||
mutable std::unique_ptr<Json::Value const> userDocumentation;
|
mutable std::unique_ptr<Json::Value const> userDocumentation;
|
||||||
mutable std::unique_ptr<Json::Value const> devDocumentation;
|
mutable std::unique_ptr<Json::Value const> devDocumentation;
|
||||||
mutable std::unique_ptr<std::string const> sourceMapping;
|
mutable std::unique_ptr<std::string const> 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.
|
/// 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;
|
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.
|
/// @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.
|
/// 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;
|
Json::Value const& natspecUser(Contract const&) const;
|
||||||
|
@ -887,10 +887,12 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting
|
|||||||
string file = contractName.substr(0, colon);
|
string file = contractName.substr(0, colon);
|
||||||
string name = contractName.substr(colon + 1);
|
string name = contractName.substr(colon + 1);
|
||||||
|
|
||||||
// ABI, documentation and metadata
|
// ABI, storage layout, documentation and metadata
|
||||||
Json::Value contractData(Json::objectValue);
|
Json::Value contractData(Json::objectValue);
|
||||||
if (isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "abi", wildcardMatchesExperimental))
|
if (isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "abi", wildcardMatchesExperimental))
|
||||||
contractData["abi"] = compilerStack.contractABI(contractName);
|
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))
|
if (isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "metadata", wildcardMatchesExperimental))
|
||||||
contractData["metadata"] = compilerStack.metadata(contractName);
|
contractData["metadata"] = compilerStack.metadata(contractName);
|
||||||
if (isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "userdoc", wildcardMatchesExperimental))
|
if (isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "userdoc", wildcardMatchesExperimental))
|
||||||
|
119
libsolidity/interface/StorageLayout.cpp
Normal file
119
libsolidity/interface/StorageLayout.cpp
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <libsolidity/interface/StorageLayout.h>
|
||||||
|
|
||||||
|
#include <libsolidity/ast/TypeProvider.h>
|
||||||
|
|
||||||
|
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<TypeType const*>(_contractDef.type());
|
||||||
|
solAssert(typeType, "");
|
||||||
|
auto contractType = dynamic_cast<ContractType const*>(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<StructType const*>(_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<MappingType const*>(_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<ArrayType const*>(_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<ReferenceType const*>(_type))
|
||||||
|
return TypeProvider::withLocationIfReference(refType->location(), _type)->richIdentifier();
|
||||||
|
return _type->richIdentifier();
|
||||||
|
}
|
58
libsolidity/interface/StorageLayout.h
Normal file
58
libsolidity/interface/StorageLayout.h
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Generates the storage layout of a contract.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <libsolidity/ast/AST.h>
|
||||||
|
#include <libsolidity/ast/Types.h>
|
||||||
|
|
||||||
|
#include <json/json.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
16
test/cmdlineTests/storage_layout_bytes/input.json
Normal file
16
test/cmdlineTests/storage_layout_bytes/input.json
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"language": "Solidity",
|
||||||
|
"sources": {
|
||||||
|
"fileA": {
|
||||||
|
"content": "contract A { bytes s1 = \"test\"; bytes s2; }"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"outputSelection": {
|
||||||
|
"fileA": {
|
||||||
|
"A": [ "storageLayout" ],
|
||||||
|
"": [ "storageLayout" ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
4
test/cmdlineTests/storage_layout_bytes/output.json
Normal file
4
test/cmdlineTests/storage_layout_bytes/output.json
Normal file
@ -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}}}
|
16
test/cmdlineTests/storage_layout_dyn_array/input.json
Normal file
16
test/cmdlineTests/storage_layout_dyn_array/input.json
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"language": "Solidity",
|
||||||
|
"sources": {
|
||||||
|
"fileA": {
|
||||||
|
"content": "contract A { uint[] array1; bool[] array2; }"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"outputSelection": {
|
||||||
|
"fileA": {
|
||||||
|
"A": [ "storageLayout" ],
|
||||||
|
"": [ "storageLayout" ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
4
test/cmdlineTests/storage_layout_dyn_array/output.json
Normal file
4
test/cmdlineTests/storage_layout_dyn_array/output.json
Normal file
@ -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}}}
|
16
test/cmdlineTests/storage_layout_many/input.json
Normal file
16
test/cmdlineTests/storage_layout_many/input.json
Normal file
@ -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" ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
4
test/cmdlineTests/storage_layout_many/output.json
Normal file
4
test/cmdlineTests/storage_layout_many/output.json
Normal file
@ -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}}}
|
16
test/cmdlineTests/storage_layout_mapping/input.json
Normal file
16
test/cmdlineTests/storage_layout_mapping/input.json
Normal file
@ -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" ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
4
test/cmdlineTests/storage_layout_mapping/output.json
Normal file
4
test/cmdlineTests/storage_layout_mapping/output.json
Normal file
@ -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}}}
|
16
test/cmdlineTests/storage_layout_smoke/input.json
Normal file
16
test/cmdlineTests/storage_layout_smoke/input.json
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"language": "Solidity",
|
||||||
|
"sources": {
|
||||||
|
"fileA": {
|
||||||
|
"content": "contract A { }"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"outputSelection": {
|
||||||
|
"fileA": {
|
||||||
|
"A": [ "storageLayout" ],
|
||||||
|
"": [ "storageLayout" ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
4
test/cmdlineTests/storage_layout_smoke/output.json
Normal file
4
test/cmdlineTests/storage_layout_smoke/output.json
Normal file
@ -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}}}
|
@ -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" ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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}}}
|
16
test/cmdlineTests/storage_layout_string/input.json
Normal file
16
test/cmdlineTests/storage_layout_string/input.json
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"language": "Solidity",
|
||||||
|
"sources": {
|
||||||
|
"fileA": {
|
||||||
|
"content": "contract A { string s1 = \"test\"; string s2; }"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"outputSelection": {
|
||||||
|
"fileA": {
|
||||||
|
"A": [ "storageLayout" ],
|
||||||
|
"": [ "storageLayout" ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
4
test/cmdlineTests/storage_layout_string/output.json
Normal file
4
test/cmdlineTests/storage_layout_string/output.json
Normal file
@ -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}}}
|
16
test/cmdlineTests/storage_layout_struct/input.json
Normal file
16
test/cmdlineTests/storage_layout_struct/input.json
Normal file
@ -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" ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
4
test/cmdlineTests/storage_layout_struct/output.json
Normal file
4
test/cmdlineTests/storage_layout_struct/output.json
Normal file
@ -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}}}
|
16
test/cmdlineTests/storage_layout_struct_packed/input.json
Normal file
16
test/cmdlineTests/storage_layout_struct_packed/input.json
Normal file
@ -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" ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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}}}
|
16
test/cmdlineTests/storage_layout_value_types/input.json
Normal file
16
test/cmdlineTests/storage_layout_value_types/input.json
Normal file
@ -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" ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
4
test/cmdlineTests/storage_layout_value_types/output.json
Normal file
4
test/cmdlineTests/storage_layout_value_types/output.json
Normal file
@ -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}}}
|
@ -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" ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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}}}
|
Loading…
Reference in New Issue
Block a user