mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Create option for metadata hash
This commit is contained in:
parent
c72d1ffb65
commit
d685554980
@ -4,10 +4,12 @@ Breaking changes:
|
||||
* ABI: remove the deprecated ``constant`` and ``payable`` fields.
|
||||
* ABI: the ``type`` field is now required and no longer specified to default to ``function``.
|
||||
* Commandline interface: remove the text-based ast printer (``--ast``).
|
||||
* Command line interface: Switch to the new error reporter by default. ``--old-reporter`` falls back to the deprecated old error reporter.
|
||||
* Command line interface: Add option to disable or choose hash method between IPFS and Swarm for the bytecode metadata.
|
||||
* General: Disallow explicit conversions from external function types to ``address`` and add a member called ``address`` to them as replacement.
|
||||
* General: New reserved keywords: ``virtual``.
|
||||
* Standard JSON Interface: Add option to disable or choose hash method between IPFS and Swarm for the bytecode metadata.
|
||||
* Type checker: Resulting type of exponentiation is equal to the type of the base. Also allow signed types for the base.
|
||||
* Command line interface: Switch to the new error reporter by default. ``--old-reporter`` falls back to the deprecated old error reporter.
|
||||
|
||||
|
||||
Language Features:
|
||||
|
@ -10,16 +10,18 @@ this file to query the compiler version, the sources used, the ABI and NatSpec
|
||||
documentation to more safely interact with the contract and verify its source
|
||||
code.
|
||||
|
||||
The compiler appends a Swarm hash of the metadata file to the end of the
|
||||
bytecode (for details, see below) of each contract, so that you can retrieve
|
||||
the file in an authenticated way without having to resort to a centralized
|
||||
data provider.
|
||||
The compiler appends by default the IPFS hash of the metadata file to the end
|
||||
of the bytecode (for details, see below) of each contract, so that you can
|
||||
retrieve the file in an authenticated way without having to resort to a
|
||||
centralized data provider. The other available options are the Swarm hash and
|
||||
not appending the metadata hash to the bytecode. These can be configured via
|
||||
the :ref:`Standard JSON Interface<compiler-api>`.
|
||||
|
||||
You have to publish the metadata file to Swarm (or another service) so that
|
||||
others can access it. You create the file by using the ``solc --metadata``
|
||||
You have to publish the metadata file to IPFS, Swarm, or another service so
|
||||
that others can access it. You create the file by using the ``solc --metadata``
|
||||
command that generates a file called ``ContractName_meta.json``. It contains
|
||||
Swarm references to the source code, so you have to upload all source files and
|
||||
the metadata file.
|
||||
IPFS and Swarm references to the source code, so you have to upload all source
|
||||
files and the metadata file.
|
||||
|
||||
The metadata file has the following format. The example below is presented in a
|
||||
human-readable way. Properly formatted metadata should use quotes correctly,
|
||||
@ -86,7 +88,9 @@ explanatory purposes.
|
||||
},
|
||||
metadata: {
|
||||
// Reflects the setting used in the input json, defaults to false
|
||||
useLiteralContent: true
|
||||
useLiteralContent: true,
|
||||
// Reflects the setting used in the input json, defaults to "ipfs"
|
||||
bytecodeHash: "ipfs"
|
||||
}
|
||||
// Required for Solidity: File and name of the contract or library this
|
||||
// metadata is created for.
|
||||
@ -111,8 +115,8 @@ explanatory purposes.
|
||||
}
|
||||
|
||||
.. warning::
|
||||
Since the bytecode of the resulting contract contains the metadata hash, any
|
||||
change to the metadata results in a change of the bytecode. This includes
|
||||
Since the bytecode of the resulting contract contains the metadata hash by default, any
|
||||
change to the metadata might result in a change of the bytecode. This includes
|
||||
changes to a filename or path, and since the metadata includes a hash of all the
|
||||
sources used, a single whitespace change results in different metadata, and
|
||||
different bytecode.
|
||||
@ -124,7 +128,7 @@ Encoding of the Metadata Hash in the Bytecode
|
||||
=============================================
|
||||
|
||||
Because we might support other ways to retrieve the metadata file in the future,
|
||||
the mapping ``{"bzzr1": <Swarm hash>, "solc": <compiler version>}`` is stored
|
||||
the mapping ``{"ipfs": <IPFS hash>, "solc": <compiler version>}`` is stored
|
||||
`CBOR <https://tools.ietf.org/html/rfc7049>`_-encoded. Since the mapping might
|
||||
contain more keys (see below) and the beginning of that
|
||||
encoding is not easy to find, its length is added in a two-byte big-endian
|
||||
@ -132,12 +136,12 @@ encoding. The current version of the Solidity compiler usually adds the followin
|
||||
to the end of the deployed bytecode::
|
||||
|
||||
0xa2
|
||||
0x65 'b' 'z' 'z' 'r' '1' 0x58 0x20 <32 bytes swarm hash>
|
||||
0x64 'i' 'p' 'f' 's' 0x58 0x22 <34 bytes IPFS hash>
|
||||
0x64 's' 'o' 'l' 'c' 0x43 <3 byte version encoding>
|
||||
0x00 0x32
|
||||
|
||||
So in order to retrieve the data, the end of the deployed bytecode can be checked
|
||||
to match that pattern and use the Swarm hash to retrieve the file.
|
||||
to match that pattern and use the IPFS hash to retrieve the file.
|
||||
|
||||
Whereas release builds of solc use a 3 byte encoding of the version as shown
|
||||
above (one byte each for major, minor and patch version number), prerelease builds
|
||||
@ -145,25 +149,25 @@ will instead use a complete version string including commit hash and build date.
|
||||
|
||||
.. note::
|
||||
The CBOR mapping can also contain other keys, so it is better to fully
|
||||
decode the data instead of relying on it starting with ``0xa265``.
|
||||
decode the data instead of relying on it starting with ``0xa264``.
|
||||
For example, if any experimental features that affect code generation
|
||||
are used, the mapping will also contain ``"experimental": true``.
|
||||
|
||||
.. note::
|
||||
The compiler currently uses the "swarm version 1" hash of the metadata,
|
||||
but this might change in the future, so do not rely on this sequence
|
||||
to start with ``0xa2 0x65 'b' 'z' 'z' 'r' '1'``. We might also
|
||||
add additional data to this CBOR structure, so the
|
||||
best option is to use a proper CBOR parser.
|
||||
The compiler currently uses the IPFS hash of the metadata by default, but
|
||||
it may also use the bzzr1 hash or some other hash in the future, so do
|
||||
not rely on this sequence to start with ``0xa2 0x64 'i' 'p' 'f' 's'``. We
|
||||
might also add additional data to this CBOR structure, so the best option
|
||||
is to use a proper CBOR parser.
|
||||
|
||||
|
||||
Usage for Automatic Interface Generation and NatSpec
|
||||
====================================================
|
||||
|
||||
The metadata is used in the following way: A component that wants to interact
|
||||
with a contract (e.g. Mist or any wallet) retrieves the code of the contract, from that
|
||||
the Swarm hash of a file which is then retrieved.
|
||||
That file is JSON-decoded into a structure like above.
|
||||
with a contract (e.g. Mist or any wallet) retrieves the code of the contract,
|
||||
from that the IPFS/Swarm hash of a file which is then retrieved. That file
|
||||
is JSON-decoded into a structure like above.
|
||||
|
||||
The component can then use the ABI to automatically generate a rudimentary
|
||||
user interface for the contract.
|
||||
@ -177,7 +181,7 @@ For additional information, read :doc:`Ethereum Natural Language Specification (
|
||||
Usage for Source Code Verification
|
||||
==================================
|
||||
|
||||
In order to verify the compilation, sources can be retrieved from Swarm
|
||||
In order to verify the compilation, sources can be retrieved from IPFS/Swarm
|
||||
via the link in the metadata file.
|
||||
The compiler of the correct version (which is checked to be part of the "official" compilers)
|
||||
is invoked on that input with the specified settings. The resulting
|
||||
|
@ -236,7 +236,12 @@ Input Description
|
||||
// Metadata settings (optional)
|
||||
"metadata": {
|
||||
// Use only literal content and not URLs (false by default)
|
||||
"useLiteralContent": true
|
||||
"useLiteralContent": true,
|
||||
// Use the given hash method for the metadata hash that is appended to the bytecode.
|
||||
// The metadata hash can be removed from the bytecode via option "none".
|
||||
// The other options are "ipfs" and "bzzr1".
|
||||
// If the option is omitted, "ipfs" is used by default.
|
||||
"bytecodeHash": "ipfs"
|
||||
},
|
||||
// Addresses of the libraries. If not all libraries are given here,
|
||||
// it can result in unlinked objects whose output data is different.
|
||||
|
@ -159,6 +159,13 @@ void CompilerStack::useMetadataLiteralSources(bool _metadataLiteralSources)
|
||||
m_metadataLiteralSources = _metadataLiteralSources;
|
||||
}
|
||||
|
||||
void CompilerStack::setMetadataHash(MetadataHash _metadataHash)
|
||||
{
|
||||
if (m_stackState >= ParsingPerformed)
|
||||
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Must set metadata hash before parsing."));
|
||||
m_metadataHash = _metadataHash;
|
||||
}
|
||||
|
||||
void CompilerStack::addSMTLib2Response(h256 const& _hash, string const& _response)
|
||||
{
|
||||
if (m_stackState >= ParsingPerformed)
|
||||
@ -182,6 +189,7 @@ void CompilerStack::reset(bool _keepSettings)
|
||||
m_generateEWasm = false;
|
||||
m_optimiserSettings = OptimiserSettings::minimal();
|
||||
m_metadataLiteralSources = false;
|
||||
m_metadataHash = MetadataHash::IPFS;
|
||||
}
|
||||
m_globalContext.reset();
|
||||
m_scopes.clear();
|
||||
@ -1155,6 +1163,10 @@ string CompilerStack::createMetadata(Contract const& _contract) const
|
||||
|
||||
if (m_metadataLiteralSources)
|
||||
meta["settings"]["metadata"]["useLiteralContent"] = true;
|
||||
|
||||
static vector<string> hashes{"ipfs", "bzzr1", "none"};
|
||||
meta["settings"]["metadata"]["bytecodeHash"] = hashes.at(unsigned(m_metadataHash));
|
||||
|
||||
meta["settings"]["evmVersion"] = m_evmVersion.name();
|
||||
meta["settings"]["compilationTarget"][_contract.contract->sourceUnitName()] =
|
||||
_contract.contract->annotation().canonicalName;
|
||||
@ -1263,7 +1275,17 @@ private:
|
||||
bytes CompilerStack::createCBORMetadata(string const& _metadata, bool _experimentalMode)
|
||||
{
|
||||
MetadataCBOREncoder encoder;
|
||||
encoder.pushBytes("bzzr1", dev::bzzr1Hash(_metadata).asBytes());
|
||||
|
||||
if (m_metadataHash == MetadataHash::IPFS)
|
||||
{
|
||||
solAssert(_metadata.length() < 1024 * 256, "Metadata too large.");
|
||||
encoder.pushBytes("ipfs", dev::ipfsHash(_metadata));
|
||||
}
|
||||
else if (m_metadataHash == MetadataHash::Bzzr1)
|
||||
encoder.pushBytes("bzzr1", dev::bzzr1Hash(_metadata).asBytes());
|
||||
else
|
||||
solAssert(m_metadataHash == MetadataHash::None, "Invalid metadata hash");
|
||||
|
||||
if (_experimentalMode)
|
||||
encoder.pushBool("experimental", true);
|
||||
if (m_release)
|
||||
|
@ -92,6 +92,12 @@ public:
|
||||
CompilationSuccessful
|
||||
};
|
||||
|
||||
enum class MetadataHash {
|
||||
IPFS,
|
||||
Bzzr1,
|
||||
None
|
||||
};
|
||||
|
||||
struct Remapping
|
||||
{
|
||||
std::string context;
|
||||
@ -171,6 +177,11 @@ public:
|
||||
/// Must be set before parsing.
|
||||
void useMetadataLiteralSources(bool _metadataLiteralSources);
|
||||
|
||||
/// Sets whether and which hash should be used
|
||||
/// to store the metadata in the bytecode.
|
||||
/// @param _metadataHash can be IPFS, Bzzr1, None
|
||||
void setMetadataHash(MetadataHash _metadataHash);
|
||||
|
||||
/// Sets the sources. Must be set before parsing.
|
||||
void setSources(StringMap _sources);
|
||||
|
||||
@ -418,6 +429,7 @@ private:
|
||||
langutil::ErrorList m_errorList;
|
||||
langutil::ErrorReporter m_errorReporter;
|
||||
bool m_metadataLiteralSources = false;
|
||||
MetadataHash m_metadataHash = MetadataHash::IPFS;
|
||||
bool m_parserErrorRecovery = false;
|
||||
State m_stackState = Empty;
|
||||
/// Whether or not there has been an error during processing.
|
||||
|
@ -378,9 +378,16 @@ boost::optional<Json::Value> checkOptimizerDetail(Json::Value const& _details, s
|
||||
|
||||
boost::optional<Json::Value> checkMetadataKeys(Json::Value const& _input)
|
||||
{
|
||||
if (_input.isObject() && _input.isMember("useLiteralContent") && !_input["useLiteralContent"].isBool())
|
||||
return formatFatalError("JSONError", "\"settings.metadata.useLiteralContent\" must be Boolean");
|
||||
static set<string> keys{"useLiteralContent"};
|
||||
if (_input.isObject())
|
||||
{
|
||||
if (_input.isMember("useLiteralContent") && !_input["useLiteralContent"].isBool())
|
||||
return formatFatalError("JSONError", "\"settings.metadata.useLiteralContent\" must be Boolean");
|
||||
|
||||
static set<string> hashes{"ipfs", "bzzr1", "none"};
|
||||
if (_input.isMember("bytecodeHash") && !hashes.count(_input["bytecodeHash"].asString()))
|
||||
return formatFatalError("JSONError", "\"settings.metadata.bytecodeHash\" must be \"ipfs\", \"bzzr1\" or \"none\"");
|
||||
}
|
||||
static set<string> keys{"useLiteralContent", "bytecodeHash"};
|
||||
return checkKeys(_input, keys, "settings.metadata");
|
||||
}
|
||||
|
||||
@ -710,6 +717,16 @@ boost::variant<StandardCompiler::InputsAndSettings, Json::Value> StandardCompile
|
||||
return *result;
|
||||
|
||||
ret.metadataLiteralSources = metadataSettings.get("useLiteralContent", Json::Value(false)).asBool();
|
||||
if (metadataSettings.isMember("bytecodeHash"))
|
||||
{
|
||||
auto metadataHash = metadataSettings["bytecodeHash"].asString();
|
||||
ret.metadataHash =
|
||||
metadataHash == "ipfs" ?
|
||||
CompilerStack::MetadataHash::IPFS :
|
||||
metadataHash == "bzzr1" ?
|
||||
CompilerStack::MetadataHash::Bzzr1 :
|
||||
CompilerStack::MetadataHash::None;
|
||||
}
|
||||
|
||||
Json::Value outputSelection = settings.get("outputSelection", Json::Value());
|
||||
|
||||
@ -735,6 +752,7 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting
|
||||
compilerStack.setOptimiserSettings(std::move(_inputsAndSettings.optimiserSettings));
|
||||
compilerStack.setLibraries(_inputsAndSettings.libraries);
|
||||
compilerStack.useMetadataLiteralSources(_inputsAndSettings.metadataLiteralSources);
|
||||
compilerStack.setMetadataHash(_inputsAndSettings.metadataHash);
|
||||
compilerStack.setRequestedContractNames(requestedContractNames(_inputsAndSettings.outputSelection));
|
||||
|
||||
compilerStack.enableIRGeneration(isIRRequested(_inputsAndSettings.outputSelection));
|
||||
|
@ -68,6 +68,7 @@ private:
|
||||
OptimiserSettings optimiserSettings = OptimiserSettings::minimal();
|
||||
std::map<std::string, h160> libraries;
|
||||
bool metadataLiteralSources = false;
|
||||
CompilerStack::MetadataHash metadataHash = CompilerStack::MetadataHash::IPFS;
|
||||
Json::Value outputSelection;
|
||||
};
|
||||
|
||||
|
@ -122,15 +122,18 @@ static string const g_strInputFile = "input-file";
|
||||
static string const g_strInterface = "interface";
|
||||
static string const g_strYul = "yul";
|
||||
static string const g_strIR = "ir";
|
||||
static string const g_strIPFS = "ipfs";
|
||||
static string const g_strEWasm = "ewasm";
|
||||
static string const g_strLicense = "license";
|
||||
static string const g_strLibraries = "libraries";
|
||||
static string const g_strLink = "link";
|
||||
static string const g_strMachine = "machine";
|
||||
static string const g_strMetadata = "metadata";
|
||||
static string const g_strMetadataHash = "metadata-hash";
|
||||
static string const g_strMetadataLiteral = "metadata-literal";
|
||||
static string const g_strNatspecDev = "devdoc";
|
||||
static string const g_strNatspecUser = "userdoc";
|
||||
static string const g_strNone = "none";
|
||||
static string const g_strOpcodes = "opcodes";
|
||||
static string const g_strOptimize = "optimize";
|
||||
static string const g_strOptimizeRuns = "optimize-runs";
|
||||
@ -144,6 +147,7 @@ static string const g_strSrcMap = "srcmap";
|
||||
static string const g_strSrcMapRuntime = "srcmap-runtime";
|
||||
static string const g_strStandardJSON = "standard-json";
|
||||
static string const g_strStrictAssembly = "strict-assembly";
|
||||
static string const g_strSwarm = "swarm";
|
||||
static string const g_strPrettyJson = "pretty-json";
|
||||
static string const g_strVersion = "version";
|
||||
static string const g_strIgnoreMissingFiles = "ignore-missing";
|
||||
@ -174,6 +178,7 @@ static string const g_argLibraries = g_strLibraries;
|
||||
static string const g_argLink = g_strLink;
|
||||
static string const g_argMachine = g_strMachine;
|
||||
static string const g_argMetadata = g_strMetadata;
|
||||
static string const g_argMetadataHash = g_strMetadataHash;
|
||||
static string const g_argMetadataLiteral = g_strMetadataLiteral;
|
||||
static string const g_argNatspecDev = g_strNatspecDev;
|
||||
static string const g_argNatspecUser = g_strNatspecUser;
|
||||
@ -218,6 +223,14 @@ static set<string> const g_machineArgs
|
||||
g_streWasm
|
||||
};
|
||||
|
||||
/// Possible arguments to for --metadata-hash
|
||||
static set<string> const g_metadataHashArgs
|
||||
{
|
||||
g_strIPFS,
|
||||
g_strSwarm,
|
||||
g_strNone
|
||||
};
|
||||
|
||||
static void version()
|
||||
{
|
||||
sout() <<
|
||||
@ -696,7 +709,12 @@ Allowed options)",
|
||||
"Switch to linker mode, ignoring all options apart from --libraries "
|
||||
"and modify binaries in place."
|
||||
)
|
||||
(g_argMetadataLiteral.c_str(), "Store referenced sources are literal data in the metadata output.")
|
||||
(
|
||||
g_argMetadataHash.c_str(),
|
||||
po::value<string>()->value_name(boost::join(g_metadataHashArgs, ",")),
|
||||
"Choose hash method for the bytecode metadata or disable it."
|
||||
)
|
||||
(g_argMetadataLiteral.c_str(), "Store referenced sources as literal data in the metadata output.")
|
||||
(
|
||||
g_argAllowPaths.c_str(),
|
||||
po::value<string>()->value_name("path(s)"),
|
||||
@ -923,6 +941,22 @@ bool CommandLineInterface::processInput()
|
||||
return link();
|
||||
}
|
||||
|
||||
if (m_args.count(g_argMetadataHash))
|
||||
{
|
||||
string hashStr = m_args[g_argMetadataHash].as<string>();
|
||||
if (hashStr == g_strIPFS)
|
||||
m_metadataHash = CompilerStack::MetadataHash::IPFS;
|
||||
else if (hashStr == g_strSwarm)
|
||||
m_metadataHash = CompilerStack::MetadataHash::Bzzr1;
|
||||
else if (hashStr == g_strNone)
|
||||
m_metadataHash = CompilerStack::MetadataHash::None;
|
||||
else
|
||||
{
|
||||
serr() << "Invalid option for --metadata-hash: " << hashStr << endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
m_compiler.reset(new CompilerStack(fileReader));
|
||||
|
||||
unique_ptr<SourceReferenceFormatter> formatter;
|
||||
@ -935,6 +969,8 @@ bool CommandLineInterface::processInput()
|
||||
{
|
||||
if (m_args.count(g_argMetadataLiteral) > 0)
|
||||
m_compiler->useMetadataLiteralSources(true);
|
||||
if (m_args.count(g_argMetadataHash))
|
||||
m_compiler->setMetadataHash(m_metadataHash);
|
||||
if (m_args.count(g_argInputFile))
|
||||
m_compiler->setRemappings(m_remappings);
|
||||
m_compiler->setSources(m_sourceCodes);
|
||||
|
@ -111,6 +111,8 @@ private:
|
||||
std::unique_ptr<dev::solidity::CompilerStack> m_compiler;
|
||||
/// EVM version to use
|
||||
langutil::EVMVersion m_evmVersion;
|
||||
/// Chosen hash method for the bytecode metadata.
|
||||
CompilerStack::MetadataHash m_metadataHash = CompilerStack::MetadataHash::IPFS;
|
||||
/// Whether or not to colorize diagnostics output.
|
||||
bool m_coloredOutput = true;
|
||||
};
|
||||
|
@ -41,9 +41,9 @@ bytes onlyMetadata(bytes const& _bytecode)
|
||||
size_t metadataSize = (_bytecode[size - 2] << 8) + _bytecode[size - 1];
|
||||
if (size < (metadataSize + 2))
|
||||
return bytes{};
|
||||
// Sanity check: assume the first byte is a fixed-size CBOR array with either 2 or 3 entries
|
||||
// Sanity check: assume the first byte is a fixed-size CBOR array with 1, 2 or 3 entries
|
||||
unsigned char firstByte = _bytecode[size - metadataSize - 2];
|
||||
if (firstByte != 0xa2 && firstByte != 0xa3)
|
||||
if (firstByte != 0xa1 && firstByte != 0xa2 && firstByte != 0xa3)
|
||||
return bytes{};
|
||||
return bytes(_bytecode.end() - metadataSize - 2, _bytecode.end() - 2);
|
||||
}
|
||||
@ -185,7 +185,9 @@ bool isValidMetadata(string const& _metadata)
|
||||
!metadata.isMember("settings") ||
|
||||
!metadata.isMember("sources") ||
|
||||
!metadata.isMember("output") ||
|
||||
!metadata["settings"].isMember("evmVersion")
|
||||
!metadata["settings"].isMember("evmVersion") ||
|
||||
!metadata["settings"].isMember("metadata") ||
|
||||
!metadata["settings"]["metadata"].isMember("bytecodeHash")
|
||||
)
|
||||
return false;
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
||||
*/
|
||||
|
||||
#include <test/libsolidity/SolidityExecutionFramework.h>
|
||||
#include <libdevcore/SwarmHash.h>
|
||||
#include <libdevcore/IpfsHash.h>
|
||||
#include <libevmasm/GasMeter.h>
|
||||
|
||||
#include <cmath>
|
||||
@ -40,18 +40,18 @@ namespace test
|
||||
#define CHECK_DEPLOY_GAS(_gasNoOpt, _gasOpt) \
|
||||
do \
|
||||
{ \
|
||||
u256 bzzr1Cost = GasMeter::dataGas(dev::bzzr1Hash(m_compiler.metadata(m_compiler.lastContractName())).asBytes(), true); \
|
||||
u256 ipfsCost = GasMeter::dataGas(dev::ipfsHash(m_compiler.metadata(m_compiler.lastContractName())), true); \
|
||||
u256 gasOpt{_gasOpt}; \
|
||||
u256 gasNoOpt{_gasNoOpt}; \
|
||||
u256 gas = m_optimiserSettings == OptimiserSettings::minimal() ? gasNoOpt : gasOpt; \
|
||||
BOOST_CHECK_MESSAGE( \
|
||||
m_gasUsed >= bzzr1Cost, \
|
||||
m_gasUsed >= ipfsCost, \
|
||||
"Gas used: " + \
|
||||
m_gasUsed.str() + \
|
||||
" is less than the data cost for the bzzr1 hash: " + \
|
||||
u256(bzzr1Cost).str() \
|
||||
" is less than the data cost for the IPFS hash: " + \
|
||||
u256(ipfsCost).str() \
|
||||
); \
|
||||
u256 gasUsed = m_gasUsed - bzzr1Cost; \
|
||||
u256 gasUsed = m_gasUsed - ipfsCost; \
|
||||
BOOST_CHECK_MESSAGE( \
|
||||
gas == gasUsed, \
|
||||
"Gas used: " + \
|
||||
@ -96,17 +96,18 @@ BOOST_AUTO_TEST_CASE(string_storage)
|
||||
compileAndRun(sourceCode);
|
||||
|
||||
if (Options::get().evmVersion() <= EVMVersion::byzantium())
|
||||
CHECK_DEPLOY_GAS(134071, 130763);
|
||||
CHECK_DEPLOY_GAS(134209, 130895);
|
||||
// This is only correct on >=Constantinople.
|
||||
else if (Options::get().useABIEncoderV2)
|
||||
{
|
||||
if (Options::get().optimizeYul)
|
||||
CHECK_DEPLOY_GAS(151455, 127653);
|
||||
CHECK_DEPLOY_GAS(127785, 127785);
|
||||
else
|
||||
CHECK_DEPLOY_GAS(151455, 135371);
|
||||
CHECK_DEPLOY_GAS(151587, 135371);
|
||||
}
|
||||
else
|
||||
CHECK_DEPLOY_GAS(126861, 119591);
|
||||
CHECK_DEPLOY_GAS(126993, 119723);
|
||||
|
||||
if (Options::get().evmVersion() >= EVMVersion::byzantium())
|
||||
{
|
||||
callContractFunction("f()");
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <libsolidity/interface/CompilerStack.h>
|
||||
#include <libsolidity/interface/Version.h>
|
||||
#include <libdevcore/SwarmHash.h>
|
||||
#include <libdevcore/IpfsHash.h>
|
||||
#include <libdevcore/JSON.h>
|
||||
|
||||
using namespace std;
|
||||
@ -60,28 +61,54 @@ BOOST_AUTO_TEST_CASE(metadata_stamp)
|
||||
}
|
||||
)";
|
||||
for (auto release: std::set<bool>{true, VersionIsRelease})
|
||||
{
|
||||
CompilerStack compilerStack;
|
||||
compilerStack.overwriteReleaseFlag(release);
|
||||
compilerStack.setSources({{"", std::string(sourceCode)}});
|
||||
compilerStack.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
compilerStack.setOptimiserSettings(dev::test::Options::get().optimize);
|
||||
BOOST_REQUIRE_MESSAGE(compilerStack.compile(), "Compiling contract failed");
|
||||
bytes const& bytecode = compilerStack.runtimeObject("test").bytecode;
|
||||
std::string const& metadata = compilerStack.metadata("test");
|
||||
BOOST_CHECK(dev::test::isValidMetadata(metadata));
|
||||
bytes hash = dev::bzzr1Hash(metadata).asBytes();
|
||||
BOOST_REQUIRE(hash.size() == 32);
|
||||
auto const cborMetadata = requireParsedCBORMetadata(bytecode);
|
||||
BOOST_CHECK(cborMetadata.size() == 2);
|
||||
BOOST_CHECK(cborMetadata.count("solc") == 1);
|
||||
if (release)
|
||||
BOOST_CHECK(cborMetadata.at("solc") == toHex(VersionCompactBytes));
|
||||
else
|
||||
BOOST_CHECK(cborMetadata.at("solc") == VersionStringStrict);
|
||||
BOOST_CHECK(cborMetadata.count("bzzr1") == 1);
|
||||
BOOST_CHECK(cborMetadata.at("bzzr1") == toHex(hash));
|
||||
}
|
||||
for (auto metadataHash: set<CompilerStack::MetadataHash>{
|
||||
CompilerStack::MetadataHash::IPFS,
|
||||
CompilerStack::MetadataHash::Bzzr1,
|
||||
CompilerStack::MetadataHash::None
|
||||
})
|
||||
{
|
||||
CompilerStack compilerStack;
|
||||
compilerStack.overwriteReleaseFlag(release);
|
||||
compilerStack.setSources({{"", std::string(sourceCode)}});
|
||||
compilerStack.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
compilerStack.setOptimiserSettings(dev::test::Options::get().optimize);
|
||||
compilerStack.setMetadataHash(metadataHash);
|
||||
BOOST_REQUIRE_MESSAGE(compilerStack.compile(), "Compiling contract failed");
|
||||
bytes const& bytecode = compilerStack.runtimeObject("test").bytecode;
|
||||
std::string const& metadata = compilerStack.metadata("test");
|
||||
BOOST_CHECK(dev::test::isValidMetadata(metadata));
|
||||
|
||||
auto const cborMetadata = requireParsedCBORMetadata(bytecode);
|
||||
if (metadataHash == CompilerStack::MetadataHash::None)
|
||||
BOOST_CHECK(cborMetadata.size() == 1);
|
||||
else
|
||||
{
|
||||
bytes hash;
|
||||
string hashMethod;
|
||||
if (metadataHash == CompilerStack::MetadataHash::IPFS)
|
||||
{
|
||||
hash = dev::ipfsHash(metadata);
|
||||
BOOST_REQUIRE(hash.size() == 34);
|
||||
hashMethod = "ipfs";
|
||||
}
|
||||
else
|
||||
{
|
||||
hash = dev::bzzr1Hash(metadata).asBytes();
|
||||
BOOST_REQUIRE(hash.size() == 32);
|
||||
hashMethod = "bzzr1";
|
||||
}
|
||||
|
||||
BOOST_CHECK(cborMetadata.size() == 2);
|
||||
BOOST_CHECK(cborMetadata.count(hashMethod) == 1);
|
||||
BOOST_CHECK(cborMetadata.at(hashMethod) == toHex(hash));
|
||||
}
|
||||
|
||||
BOOST_CHECK(cborMetadata.count("solc") == 1);
|
||||
if (release)
|
||||
BOOST_CHECK(cborMetadata.at("solc") == toHex(VersionCompactBytes));
|
||||
else
|
||||
BOOST_CHECK(cborMetadata.at("solc") == VersionStringStrict);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(metadata_stamp_experimental)
|
||||
@ -94,31 +121,57 @@ BOOST_AUTO_TEST_CASE(metadata_stamp_experimental)
|
||||
function g(function(uint) external returns (uint) x) public {}
|
||||
}
|
||||
)";
|
||||
for(auto release: std::set<bool>{true, VersionIsRelease})
|
||||
{
|
||||
CompilerStack compilerStack;
|
||||
compilerStack.overwriteReleaseFlag(release);
|
||||
compilerStack.setSources({{"", std::string(sourceCode)}});
|
||||
compilerStack.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
compilerStack.setOptimiserSettings(dev::test::Options::get().optimize);
|
||||
BOOST_REQUIRE_MESSAGE(compilerStack.compile(), "Compiling contract failed");
|
||||
bytes const& bytecode = compilerStack.runtimeObject("test").bytecode;
|
||||
std::string const& metadata = compilerStack.metadata("test");
|
||||
BOOST_CHECK(dev::test::isValidMetadata(metadata));
|
||||
bytes hash = dev::bzzr1Hash(metadata).asBytes();
|
||||
BOOST_REQUIRE(hash.size() == 32);
|
||||
auto const cborMetadata = requireParsedCBORMetadata(bytecode);
|
||||
BOOST_CHECK(cborMetadata.size() == 3);
|
||||
BOOST_CHECK(cborMetadata.count("solc") == 1);
|
||||
if (release)
|
||||
BOOST_CHECK(cborMetadata.at("solc") == toHex(VersionCompactBytes));
|
||||
else
|
||||
BOOST_CHECK(cborMetadata.at("solc") == VersionStringStrict);
|
||||
BOOST_CHECK(cborMetadata.count("bzzr1") == 1);
|
||||
BOOST_CHECK(cborMetadata.at("bzzr1") == toHex(hash));
|
||||
BOOST_CHECK(cborMetadata.count("experimental") == 1);
|
||||
BOOST_CHECK(cborMetadata.at("experimental") == "true");
|
||||
}
|
||||
for (auto release: set<bool>{true, VersionIsRelease})
|
||||
for (auto metadataHash: set<CompilerStack::MetadataHash>{
|
||||
CompilerStack::MetadataHash::IPFS,
|
||||
CompilerStack::MetadataHash::Bzzr1,
|
||||
CompilerStack::MetadataHash::None
|
||||
})
|
||||
{
|
||||
CompilerStack compilerStack;
|
||||
compilerStack.overwriteReleaseFlag(release);
|
||||
compilerStack.setSources({{"", std::string(sourceCode)}});
|
||||
compilerStack.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
compilerStack.setOptimiserSettings(dev::test::Options::get().optimize);
|
||||
compilerStack.setMetadataHash(metadataHash);
|
||||
BOOST_REQUIRE_MESSAGE(compilerStack.compile(), "Compiling contract failed");
|
||||
bytes const& bytecode = compilerStack.runtimeObject("test").bytecode;
|
||||
std::string const& metadata = compilerStack.metadata("test");
|
||||
BOOST_CHECK(dev::test::isValidMetadata(metadata));
|
||||
|
||||
auto const cborMetadata = requireParsedCBORMetadata(bytecode);
|
||||
if (metadataHash == CompilerStack::MetadataHash::None)
|
||||
BOOST_CHECK(cborMetadata.size() == 2);
|
||||
else
|
||||
{
|
||||
bytes hash;
|
||||
string hashMethod;
|
||||
if (metadataHash == CompilerStack::MetadataHash::IPFS)
|
||||
{
|
||||
hash = dev::ipfsHash(metadata);
|
||||
BOOST_REQUIRE(hash.size() == 34);
|
||||
hashMethod = "ipfs";
|
||||
}
|
||||
else
|
||||
{
|
||||
hash = dev::bzzr1Hash(metadata).asBytes();
|
||||
BOOST_REQUIRE(hash.size() == 32);
|
||||
hashMethod = "bzzr1";
|
||||
}
|
||||
|
||||
BOOST_CHECK(cborMetadata.size() == 3);
|
||||
BOOST_CHECK(cborMetadata.count(hashMethod) == 1);
|
||||
BOOST_CHECK(cborMetadata.at(hashMethod) == toHex(hash));
|
||||
}
|
||||
|
||||
BOOST_CHECK(cborMetadata.count("solc") == 1);
|
||||
if (release)
|
||||
BOOST_CHECK(cborMetadata.at("solc") == toHex(VersionCompactBytes));
|
||||
else
|
||||
BOOST_CHECK(cborMetadata.at("solc") == VersionStringStrict);
|
||||
BOOST_CHECK(cborMetadata.count("experimental") == 1);
|
||||
BOOST_CHECK(cborMetadata.at("experimental") == "true");
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(metadata_relevant_sources)
|
||||
@ -218,16 +271,13 @@ BOOST_AUTO_TEST_CASE(metadata_useLiteralContent)
|
||||
jsonParse(metadata_str, metadata);
|
||||
BOOST_CHECK(dev::test::isValidMetadata(metadata_str));
|
||||
BOOST_CHECK(metadata.isMember("settings"));
|
||||
BOOST_CHECK(metadata["settings"].isMember("metadata"));
|
||||
BOOST_CHECK(metadata["settings"]["metadata"].isMember("bytecodeHash"));
|
||||
if (_literal)
|
||||
{
|
||||
BOOST_CHECK(metadata["settings"].isMember("metadata"));
|
||||
BOOST_CHECK(metadata["settings"]["metadata"].isMember("useLiteralContent"));
|
||||
BOOST_CHECK(metadata["settings"]["metadata"]["useLiteralContent"].asBool());
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_CHECK(!metadata["settings"].isMember("metadata"));
|
||||
}
|
||||
};
|
||||
|
||||
check(sourceCode, true);
|
||||
|
@ -364,7 +364,7 @@ BOOST_AUTO_TEST_CASE(basic_compilation)
|
||||
BOOST_CHECK_EQUAL(
|
||||
dev::test::bytecodeSansMetadata(contract["evm"]["bytecode"]["object"].asString()),
|
||||
string("6080604052348015600f57600080fd5b5060") +
|
||||
(VersionIsRelease ? "3e" : toHex(bytes{uint8_t(60 + VersionStringStrict.size())})) +
|
||||
(VersionIsRelease ? "3f" : toHex(bytes{uint8_t(61 + VersionStringStrict.size())})) +
|
||||
"80601d6000396000f3fe6080604052600080fdfe"
|
||||
);
|
||||
BOOST_CHECK(contract["evm"]["assembly"].isString());
|
||||
@ -377,7 +377,7 @@ BOOST_AUTO_TEST_CASE(basic_compilation)
|
||||
"tag_1:\n /* \"fileA\":0:14 contract A { } */\n pop\n dataSize(sub_0)\n dup1\n "
|
||||
"dataOffset(sub_0)\n 0x00\n codecopy\n 0x00\n return\nstop\n\nsub_0: assembly {\n "
|
||||
"/* \"fileA\":0:14 contract A { } */\n mstore(0x40, 0x80)\n 0x00\n "
|
||||
"dup1\n revert\n\n auxdata: 0xa265627a7a72315820"
|
||||
"dup1\n revert\n\n auxdata: 0xa26469706673582212"
|
||||
) == 0);
|
||||
BOOST_CHECK(contract["evm"]["gasEstimates"].isObject());
|
||||
BOOST_CHECK_EQUAL(contract["evm"]["gasEstimates"].size(), 1);
|
||||
|
@ -14,9 +14,9 @@ contract C {
|
||||
}
|
||||
// ----
|
||||
// creation:
|
||||
// codeDepositCost: 1122600
|
||||
// codeDepositCost: 1122800
|
||||
// executionCost: 1167
|
||||
// totalCost: 1123767
|
||||
// totalCost: 1123967
|
||||
// external:
|
||||
// a(): 530
|
||||
// b(uint256): infinite
|
||||
|
@ -17,9 +17,9 @@ contract C {
|
||||
// optimize-yul: true
|
||||
// ----
|
||||
// creation:
|
||||
// codeDepositCost: 624200
|
||||
// codeDepositCost: 624400
|
||||
// executionCost: 657
|
||||
// totalCost: 624857
|
||||
// totalCost: 625057
|
||||
// external:
|
||||
// a(): 429
|
||||
// b(uint256): 884
|
||||
|
@ -13,8 +13,8 @@ contract C {
|
||||
}
|
||||
// ----
|
||||
// creation:
|
||||
// codeDepositCost: 256800
|
||||
// codeDepositCost: 257000
|
||||
// executionCost: 300
|
||||
// totalCost: 257100
|
||||
// totalCost: 257300
|
||||
// external:
|
||||
// f(): 252
|
||||
|
@ -24,9 +24,9 @@ contract Large {
|
||||
}
|
||||
// ----
|
||||
// creation:
|
||||
// codeDepositCost: 636800
|
||||
// codeDepositCost: 637000
|
||||
// executionCost: 670
|
||||
// totalCost: 637470
|
||||
// totalCost: 637670
|
||||
// external:
|
||||
// a(): 451
|
||||
// b(uint256): 846
|
||||
|
@ -27,9 +27,9 @@ contract Large {
|
||||
// optimize-runs: 2
|
||||
// ----
|
||||
// creation:
|
||||
// codeDepositCost: 260400
|
||||
// codeDepositCost: 260600
|
||||
// executionCost: 300
|
||||
// totalCost: 260700
|
||||
// totalCost: 260900
|
||||
// external:
|
||||
// a(): 398
|
||||
// b(uint256): 1105
|
||||
|
@ -11,9 +11,9 @@ contract Medium {
|
||||
}
|
||||
// ----
|
||||
// creation:
|
||||
// codeDepositCost: 253000
|
||||
// codeDepositCost: 253200
|
||||
// executionCost: 294
|
||||
// totalCost: 253294
|
||||
// totalCost: 253494
|
||||
// external:
|
||||
// a(): 428
|
||||
// b(uint256): 846
|
||||
|
@ -14,9 +14,9 @@ contract Medium {
|
||||
// optimize-runs: 2
|
||||
// ----
|
||||
// creation:
|
||||
// codeDepositCost: 140800
|
||||
// executionCost: 183
|
||||
// totalCost: 140983
|
||||
// codeDepositCost: 141000
|
||||
// executionCost: 190
|
||||
// totalCost: 141190
|
||||
// external:
|
||||
// a(): 398
|
||||
// b(uint256): 863
|
||||
|
@ -6,9 +6,9 @@ contract Small {
|
||||
}
|
||||
// ----
|
||||
// creation:
|
||||
// codeDepositCost: 83600
|
||||
// codeDepositCost: 83800
|
||||
// executionCost: 135
|
||||
// totalCost: 83735
|
||||
// totalCost: 83935
|
||||
// external:
|
||||
// fallback: 118
|
||||
// a(): 383
|
||||
|
@ -9,9 +9,9 @@ contract Small {
|
||||
// optimize-runs: 2
|
||||
// ----
|
||||
// creation:
|
||||
// codeDepositCost: 60400
|
||||
// codeDepositCost: 60600
|
||||
// executionCost: 111
|
||||
// totalCost: 60511
|
||||
// totalCost: 60711
|
||||
// external:
|
||||
// fallback: 118
|
||||
// a(): 376
|
||||
|
Loading…
Reference in New Issue
Block a user