mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #5941 from ethereum/metadata-compilerstack
Metadata should not require compilation
This commit is contained in:
commit
6c9961e040
@ -10,6 +10,7 @@ Compiler Features:
|
||||
* Inline Assembly: Consider ``extcodehash`` as part of Constantinople.
|
||||
* Inline Assembly: Instructions unavailable to the currently configured EVM are errors now.
|
||||
* SMTChecker: Do not report underflow/overflow if they always revert. This removes false positives when using ``SafeMath``.
|
||||
* Standard JSON Interface: Allow retrieving metadata without triggering compilation.
|
||||
* Static Analyzer: Warn about expressions with custom types when they have no effect.
|
||||
* Optimizer: Add new rules with constants including ``LT``, ``GT``, ``AND`` and ``BYTE``.
|
||||
* Optimizer: Add rule for shifts with constants for Constantinople.
|
||||
|
@ -631,10 +631,24 @@ Json::Value CompilerStack::methodIdentifiers(string const& _contractName) const
|
||||
|
||||
string const& CompilerStack::metadata(string const& _contractName) const
|
||||
{
|
||||
if (m_stackState != CompilationSuccessful)
|
||||
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful."));
|
||||
if (m_stackState < AnalysisSuccessful)
|
||||
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Analysis was not successful."));
|
||||
|
||||
return contract(_contractName).metadata;
|
||||
return metadata(contract(_contractName));
|
||||
}
|
||||
|
||||
string const& CompilerStack::metadata(Contract const& _contract) const
|
||||
{
|
||||
if (m_stackState < AnalysisSuccessful)
|
||||
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Analysis was not successful."));
|
||||
|
||||
solAssert(_contract.contract, "");
|
||||
|
||||
// cache the result
|
||||
if (!_contract.metadata)
|
||||
_contract.metadata.reset(new string(createMetadata(_contract)));
|
||||
|
||||
return *_contract.metadata;
|
||||
}
|
||||
|
||||
Scanner const& CompilerStack::scanner(string const& _sourceName) const
|
||||
@ -848,11 +862,8 @@ void CompilerStack::compileContract(
|
||||
shared_ptr<Compiler> compiler = make_shared<Compiler>(m_evmVersion, m_optimiserSettings);
|
||||
compiledContract.compiler = compiler;
|
||||
|
||||
string metadata = createMetadata(compiledContract);
|
||||
compiledContract.metadata = metadata;
|
||||
|
||||
bytes cborEncodedMetadata = createCBORMetadata(
|
||||
metadata,
|
||||
metadata(compiledContract),
|
||||
!onlySafeExperimentalFeaturesActivated(_contract.sourceUnit().annotation().experimentalFeatures)
|
||||
);
|
||||
|
||||
|
@ -276,7 +276,7 @@ private:
|
||||
std::shared_ptr<Compiler> compiler;
|
||||
eth::LinkerObject object; ///< Deployment object (includes the runtime sub-object).
|
||||
eth::LinkerObject runtimeObject; ///< Runtime object.
|
||||
std::string 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> userDocumentation;
|
||||
mutable std::unique_ptr<Json::Value const> devDocumentation;
|
||||
@ -339,6 +339,10 @@ private:
|
||||
/// This will generate the JSON object and store it in the Contract object if it is not present yet.
|
||||
Json::Value const& natspecDev(Contract const&) const;
|
||||
|
||||
/// @returns the Contract Metadata
|
||||
/// This will generate the metadata and store it in the Contract object if it is not present yet.
|
||||
std::string const& metadata(Contract const&) const;
|
||||
|
||||
/// @returns the offset of the entry point of the given function into the list of assembly items
|
||||
/// or zero if it is not found or does not exist.
|
||||
size_t functionEntryPoint(
|
||||
|
@ -201,7 +201,6 @@ bool isBinaryRequested(Json::Value const& _outputSelection)
|
||||
// This does not inculde "evm.methodIdentifiers" on purpose!
|
||||
static vector<string> const outputsThatRequireBinaries{
|
||||
"*",
|
||||
"metadata", // This is only generated at the end of compilation, but could be generated earlier.
|
||||
"evm.deployedBytecode", "evm.deployedBytecode.object", "evm.deployedBytecode.opcodes",
|
||||
"evm.deployedBytecode.sourceMap", "evm.deployedBytecode.linkReferences",
|
||||
"evm.bytecode", "evm.bytecode.object", "evm.bytecode.opcodes", "evm.bytecode.sourceMap",
|
||||
@ -777,7 +776,7 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
|
||||
Json::Value contractData(Json::objectValue);
|
||||
if (isArtifactRequested(outputSelection, file, name, "abi"))
|
||||
contractData["abi"] = m_compilerStack.contractABI(contractName);
|
||||
if (compilationSuccess && isArtifactRequested(outputSelection, file, name, "metadata"))
|
||||
if (isArtifactRequested(outputSelection, file, name, "metadata"))
|
||||
contractData["metadata"] = m_compilerStack.metadata(contractName);
|
||||
if (isArtifactRequested(outputSelection, file, name, "userdoc"))
|
||||
contractData["userdoc"] = m_compilerStack.natspecUser(contractName);
|
||||
|
@ -10,15 +10,32 @@ report = open("report.txt", "wb")
|
||||
|
||||
for optimize in [False, True]:
|
||||
for f in sorted(glob.glob("*.sol")):
|
||||
args = [solc, '--combined-json', 'bin,metadata', f]
|
||||
sources = {}
|
||||
sources[f] = {'content': open(f, 'r').read()}
|
||||
input = {
|
||||
'language': 'Solidity',
|
||||
'sources': sources,
|
||||
'settings': {
|
||||
'optimizer': {
|
||||
'enabled': optimize
|
||||
},
|
||||
'outputSelection': { '*': { '*': ['evm.bytecode.object', 'metadata'] } }
|
||||
}
|
||||
}
|
||||
args = [solc, '--standard-json']
|
||||
if optimize:
|
||||
args += ['--optimize']
|
||||
proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
(out, err) = proc.communicate()
|
||||
proc = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
(out, err) = proc.communicate(json.dumps(input))
|
||||
try:
|
||||
result = json.loads(out.strip())
|
||||
for contractName in sorted(result['contracts'].keys()):
|
||||
report.write(contractName + ' ' + result['contracts'][contractName]['bin'] + '\n')
|
||||
report.write(contractName + ' ' + result['contracts'][contractName]['metadata'] + '\n')
|
||||
except:
|
||||
for filename in sorted(result['contracts'].keys()):
|
||||
for contractName in sorted(result['contracts'][filename].keys()):
|
||||
contractData = result['contracts'][filename][contractName]
|
||||
if 'evm' in contractData and 'bytecode' in contractData['evm']:
|
||||
report.write(filename + ':' + contractName + ' ' + contractData['evm']['bytecode']['object'] + '\n')
|
||||
else:
|
||||
report.write(filename + ':' + contractName + ' NO BYTECODE\n')
|
||||
report.write(filename + ':' + contractName + ' ' + contractData['metadata'] + '\n')
|
||||
except KeyError:
|
||||
report.write(f + ": ERROR\n")
|
||||
|
@ -88,8 +88,12 @@ for (var optimize of [false, true])
|
||||
{
|
||||
for (var contractName in result['contracts'][filename])
|
||||
{
|
||||
console.log(filename + ':' + contractName + ' ' + result['contracts'][filename][contractName].evm.bytecode.object)
|
||||
console.log(filename + ':' + contractName + ' ' + result['contracts'][filename][contractName].metadata)
|
||||
var contractData = result['contracts'][filename][contractName];
|
||||
if (contractData.evm !== undefined && contractData.evm.bytecode !== undefined)
|
||||
console.log(filename + ':' + contractName + ' ' + contractData.evm.bytecode.object)
|
||||
else
|
||||
console.log(filename + ':' + contractName + ' NO BYTECODE')
|
||||
console.log(filename + ':' + contractName + ' ' + contractData.metadata)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1015,6 +1015,68 @@ BOOST_AUTO_TEST_CASE(optimizer_settings_details_different)
|
||||
BOOST_CHECK(optimizer["runs"].asUInt() == 600);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(metadata_without_compilation)
|
||||
{
|
||||
// NOTE: the contract code here should fail to compile due to "out of stack"
|
||||
// If the metadata is successfully returned, that means no compilation was attempted.
|
||||
char const* input = R"(
|
||||
{
|
||||
"language": "Solidity",
|
||||
"settings": {
|
||||
"outputSelection": {
|
||||
"fileA": { "A": [ "metadata" ] }
|
||||
}
|
||||
},
|
||||
"sources": {
|
||||
"fileA": {
|
||||
"content": "contract A {
|
||||
function x(uint a, uint b, uint c, uint d, uint e, uint f, uint g, uint h, uint i, uint j, uint k, uint l, uint m, uint n, uint o, uint p) pure public {}
|
||||
function y() pure public {
|
||||
uint a; uint b; uint c; uint d; uint e; uint f; uint g; uint h; uint i; uint j; uint k; uint l; uint m; uint n; uint o; uint p;
|
||||
x(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p);
|
||||
}
|
||||
}"
|
||||
}
|
||||
}
|
||||
}
|
||||
)";
|
||||
Json::Value result = compile(input);
|
||||
BOOST_CHECK(containsAtMostWarnings(result));
|
||||
Json::Value contract = getContractResult(result, "fileA", "A");
|
||||
BOOST_CHECK(contract.isObject());
|
||||
BOOST_CHECK(contract["metadata"].isString());
|
||||
BOOST_CHECK(dev::test::isValidMetadata(contract["metadata"].asString()));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(common_pattern)
|
||||
{
|
||||
char const* input = R"(
|
||||
{
|
||||
"language": "Solidity",
|
||||
"settings": {
|
||||
"outputSelection": {
|
||||
"*": {
|
||||
"*": [ "evm.bytecode.object", "metadata" ]
|
||||
}
|
||||
}
|
||||
},
|
||||
"sources": {
|
||||
"fileA": {
|
||||
"content": "contract A { function f() pure public {} }"
|
||||
}
|
||||
}
|
||||
}
|
||||
)";
|
||||
Json::Value result = compile(input);
|
||||
BOOST_CHECK(containsAtMostWarnings(result));
|
||||
Json::Value contract = getContractResult(result, "fileA", "A");
|
||||
BOOST_CHECK(contract.isObject());
|
||||
BOOST_CHECK(contract["metadata"].isString());
|
||||
BOOST_CHECK(dev::test::isValidMetadata(contract["metadata"].asString()));
|
||||
BOOST_CHECK(contract["evm"]["bytecode"].isObject());
|
||||
BOOST_CHECK(contract["evm"]["bytecode"]["object"].isString());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user