Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove old libsolc API (compileJSON, compileJSONMulti, compileJSONCallback) #5105

Merged
merged 3 commits into from
Nov 13, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ How to update your code:

Breaking Changes:
* ABI Encoder: Properly pad data from calldata (``msg.data`` and external function parameters). Use ``abi.encodePacked`` for unpadded encoding.
* C API (``libsolc`` / raw ``soljson.js``): Removed the ``version``, ``license``, ``compileSingle``, ``compileJSON``, ``compileJSONCallback`` methods
and replaced them with the ``solidity_license``, ``solidity_version`` and ``solidity_compile`` methods.
* Code Generator: Signed right shift uses proper arithmetic shift, i.e. rounding towards negative infinity. Warning: this may silently change the semantics of existing code!
* Code Generator: Revert at runtime if calldata is too short or points out of bounds. This is done inside the ``ABI decoder`` and therefore also applies to ``abi.decode()``.
* Code Generator: Use ``STATICCALL`` for ``pure`` and ``view`` functions. This was already the case in the experimental 0.5.0 mode.
Expand Down Expand Up @@ -91,7 +93,6 @@ Language Features:

Compiler Features:
* Build System: Support for Mojave version of macOS added.
* C API (``libsolc``): Export the ``solidity_license``, ``solidity_version`` and ``solidity_compile`` methods.
* Code Generator: ``CREATE2`` instruction has been updated to match EIP1014 (aka "Skinny CREATE2"). It also is accepted as part of Constantinople.
* Code Generator: ``EXTCODEHASH`` instruction has been added based on EIP1052.
* Type Checker: Nicer error message when trying to reference overloaded identifiers in inline assembly.
Expand Down
2 changes: 1 addition & 1 deletion libsolc/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
if (EMSCRIPTEN)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s EXPORTED_FUNCTIONS='[\"_solidity_license\",\"_solidity_version\",\"_solidity_compile\",\"_license\",\"_version\",\"_compileJSON\",\"_compileJSONMulti\",\"_compileJSONCallback\",\"_compileStandard\"]' -s RESERVED_FUNCTION_POINTERS=20")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s EXPORTED_FUNCTIONS='[\"_solidity_license\",\"_solidity_version\",\"_solidity_compile\"]' -s RESERVED_FUNCTION_POINTERS=20")
add_executable(soljson libsolc.cpp)
target_link_libraries(soljson PRIVATE solidity)
else()
Expand Down
228 changes: 6 additions & 222 deletions libsolc/libsolc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
/**
* @author Christian <[email protected]>
* @date 2014
* JSON interface for the solidity compiler to be used from Javascript.
* Public compiler API.
*/

#include <libsolc/libsolc.h>
Expand Down Expand Up @@ -72,193 +72,7 @@ ReadCallback::Callback wrapReadCallback(CStyleReadFileCallback _readCallback = n
return readCallback;
}

/// Translates a gas value as a string to a JSON number or null
Json::Value gasToJson(Json::Value const& _value)
{
if (_value.isObject())
{
Json::Value ret = Json::objectValue;
for (auto const& sig: _value.getMemberNames())
ret[sig] = gasToJson(_value[sig]);
return ret;
}

if (_value == "infinite")
return Json::Value(Json::nullValue);

u256 value(_value.asString());
if (value > std::numeric_limits<Json::LargestUInt>::max())
return Json::Value(Json::nullValue);
else
return Json::Value(Json::LargestUInt(value));
}

Json::Value translateGasEstimates(Json::Value const& estimates)
{
Json::Value output(Json::objectValue);

if (estimates["creation"].isObject())
{
Json::Value creation(Json::arrayValue);
creation[0] = gasToJson(estimates["creation"]["executionCost"]);
creation[1] = gasToJson(estimates["creation"]["codeDepositCost"]);
output["creation"] = creation;
}
else
output["creation"] = Json::objectValue;
output["external"] = gasToJson(estimates.get("external", Json::objectValue));
output["internal"] = gasToJson(estimates.get("internal", Json::objectValue));

return output;
}

string compile(StringMap const& _sources, bool _optimize, CStyleReadFileCallback _readCallback)
{
/// create new JSON input format
Json::Value input = Json::objectValue;
input["language"] = "Solidity";
input["sources"] = Json::objectValue;
for (auto const& source: _sources)
{
input["sources"][source.first] = Json::objectValue;
input["sources"][source.first]["content"] = source.second;
}
input["settings"] = Json::objectValue;
input["settings"]["optimizer"] = Json::objectValue;
input["settings"]["optimizer"]["enabled"] = _optimize;
input["settings"]["optimizer"]["runs"] = 200;

// Enable all SourceUnit-level outputs.
input["settings"]["outputSelection"]["*"][""][0] = "*";
// Enable all Contract-level outputs.
input["settings"]["outputSelection"]["*"]["*"][0] = "*";

StandardCompiler compiler(wrapReadCallback(_readCallback));
Json::Value ret = compiler.compile(input);

/// transform JSON to match the old format
// {
// "errors": [ "Error 1", "Error 2" ],
// "sourceList": [ "sourcename1", "sourcename2" ],
// "sources": {
// "sourcename1": {
// "AST": {}
// }
// },
// "contracts": {
// "Contract1": {
// "interface": "[...abi...]",
// "bytecode": "ff0011...",
// "runtimeBytecode": "ff0011",
// "opcodes": "PUSH 1 POP STOP",
// "metadata": "{...metadata...}",
// "functionHashes": {
// "test(uint256)": "11ff2233"
// },
// "gasEstimates": {
// "creation": [ 224, 42000 ],
// "external": {
// "11ff2233": null,
// "3322ff11": 1234
// },
// "internal": {
// }
// },
// "srcmap" = "0:1:2",
// "srcmapRuntime" = "0:1:2",
// "assembly" = {}
// }
// }
// }
Json::Value output = Json::objectValue;

if (ret.isMember("errors"))
{
output["errors"] = Json::arrayValue;
for (auto const& error: ret["errors"])
output["errors"].append(
!error["formattedMessage"].empty() ? error["formattedMessage"] : error["message"]
);
}

output["sourceList"] = Json::arrayValue;
for (auto const& source: _sources)
output["sourceList"].append(source.first);

if (ret.isMember("sources"))
{
output["sources"] = Json::objectValue;
for (auto const& sourceName: ret["sources"].getMemberNames())
{
output["sources"][sourceName] = Json::objectValue;
output["sources"][sourceName]["AST"] = ret["sources"][sourceName]["legacyAST"];
}
}

if (ret.isMember("contracts"))
{
output["contracts"] = Json::objectValue;
for (auto const& sourceName: ret["contracts"].getMemberNames())
for (auto const& contractName: ret["contracts"][sourceName].getMemberNames())
{
Json::Value contractInput = ret["contracts"][sourceName][contractName];
Json::Value contractOutput = Json::objectValue;
contractOutput["interface"] = jsonCompactPrint(contractInput["abi"]);
contractOutput["metadata"] = contractInput["metadata"];
contractOutput["functionHashes"] = contractInput["evm"]["methodIdentifiers"];
contractOutput["gasEstimates"] = translateGasEstimates(contractInput["evm"]["gasEstimates"]);
contractOutput["assembly"] = contractInput["evm"]["legacyAssembly"];
contractOutput["bytecode"] = contractInput["evm"]["bytecode"]["object"];
contractOutput["opcodes"] = contractInput["evm"]["bytecode"]["opcodes"];
contractOutput["srcmap"] = contractInput["evm"]["bytecode"]["sourceMap"];
contractOutput["runtimeBytecode"] = contractInput["evm"]["deployedBytecode"]["object"];
contractOutput["srcmapRuntime"] = contractInput["evm"]["deployedBytecode"]["sourceMap"];
output["contracts"][sourceName + ":" + contractName] = contractOutput;
}
}

try
{
return jsonCompactPrint(output);
}
catch (...)
{
return "{\"errors\":[\"Unknown error while generating JSON.\"]}";
}
}

string compileMulti(string const& _input, bool _optimize, CStyleReadFileCallback _readCallback = nullptr)
{
string errors;
Json::Value input;
if (!jsonParseStrict(_input, input, &errors))
{
Json::Value jsonErrors(Json::arrayValue);
jsonErrors.append("Error parsing input JSON: " + errors);
Json::Value output(Json::objectValue);
output["errors"] = jsonErrors;
return jsonCompactPrint(output);
}
else
{
StringMap sources;
Json::Value jsonSources = input["sources"];
if (jsonSources.isObject())
for (auto const& sourceName: jsonSources.getMemberNames())
sources[sourceName] = jsonSources[sourceName].asString();
return compile(sources, _optimize, _readCallback);
}
}

string compileSingle(string const& _input, bool _optimize)
{
StringMap sources;
sources[""] = _input;
return compile(sources, _optimize, nullptr);
}


string compileStandardInternal(string const& _input, CStyleReadFileCallback _readCallback = nullptr)
string compile(string const& _input, CStyleReadFileCallback _readCallback = nullptr)
{
StandardCompiler compiler(wrapReadCallback(_readCallback));
return compiler.compile(_input);
Expand All @@ -270,48 +84,18 @@ static string s_outputBuffer;

extern "C"
{
extern char const* license() noexcept
extern char const* solidity_license() noexcept
{
static string fullLicenseText = otherLicenses + licenseText;
return fullLicenseText.c_str();
}
extern char const* version() noexcept
{
return VersionString.c_str();
}
extern char const* compileJSON(char const* _input, bool _optimize) noexcept
{
s_outputBuffer = compileSingle(_input, _optimize);
return s_outputBuffer.c_str();
}
extern char const* compileJSONMulti(char const* _input, bool _optimize) noexcept
{
s_outputBuffer = compileMulti(_input, _optimize);
return s_outputBuffer.c_str();
}
extern char const* compileJSONCallback(char const* _input, bool _optimize, CStyleReadFileCallback _readCallback) noexcept
{
s_outputBuffer = compileMulti(_input, _optimize, _readCallback);
return s_outputBuffer.c_str();
}
extern char const* compileStandard(char const* _input, CStyleReadFileCallback _readCallback) noexcept
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm kind of leaning towards keeping this single line for now (during the release candidate time) so that projects can easily test it with truffle.

{
s_outputBuffer = compileStandardInternal(_input, _readCallback);
return s_outputBuffer.c_str();
}
extern char const* solidity_license() noexcept
{
/// todo: make this the default or an alias
return license();
}
extern char const* solidity_version() noexcept
{
/// todo: make this the default or an alias
return version();
return VersionString.c_str();
}
extern char const* solidity_compile(char const* _input, CStyleReadFileCallback _readCallback) noexcept
{
/// todo: make this the default or an alias
return compileStandard(_input, _readCallback);
s_outputBuffer = compile(_input, _readCallback);
return s_outputBuffer.c_str();
}
}
9 changes: 1 addition & 8 deletions libsolc/libsolc.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
/**
* @author Christian <[email protected]>
* @date 2014
* JSON interface for the solidity compiler to be used from Javascript.
* Public compiler API.
*/

#include <stdbool.h>
Expand All @@ -36,13 +36,6 @@ extern "C" {
/// heap-allocated and are free'd by the caller.
typedef void (*CStyleReadFileCallback)(char const* _path, char** o_contents, char** o_error);

char const* license() SOLC_NOEXCEPT;
char const* version() SOLC_NOEXCEPT;
char const* compileJSON(char const* _input, bool _optimize) SOLC_NOEXCEPT;
char const* compileJSONMulti(char const* _input, bool _optimize) SOLC_NOEXCEPT;
char const* compileJSONCallback(char const* _input, bool _optimize, CStyleReadFileCallback _readCallback) SOLC_NOEXCEPT;
char const* compileStandard(char const* _input, CStyleReadFileCallback _readCallback) SOLC_NOEXCEPT;

char const* solidity_license() SOLC_NOEXCEPT;
char const* solidity_version() SOLC_NOEXCEPT;
char const* solidity_compile(char const* _input, CStyleReadFileCallback _readCallback) SOLC_NOEXCEPT;
Expand Down
20 changes: 15 additions & 5 deletions scripts/bytecodecompare/storebytecode.sh
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,16 @@ TMPDIR=$(mktemp -d)

if [[ "$SOLC_EMSCRIPTEN" = "On" ]]
then
cp "$REPO_ROOT/build/libsolc/soljson.js" .
npm install solc
# npm install solc
git clone --depth 1 https://github.com/ethereum/solc-js.git solc-js
( cd solc-js; npm install )
cp "$REPO_ROOT/build/libsolc/soljson.js" solc-js/
cat > solc <<EOF
#!/usr/bin/env node
var process = require('process')
var fs = require('fs')
var compiler = require('solc/wrapper.js')(require('./soljson.js'))
var compiler = require('./solc-js/wrapper.js')(require('./solc-js/soljson.js'))
for (var optimize of [false, true])
{
Expand All @@ -57,7 +59,15 @@ for (var optimize of [false, true])
{
var inputs = {}
inputs[filename] = fs.readFileSync(filename).toString()
var result = compiler.compile({sources: inputs}, optimize)
var input = {
language: 'Solidity',
sources: inputs,
settings: {
optimizer: { enabled: optimize },
outputSelection: { '*': { '*': ['evm.bytecode.object', 'metadata'] } }
}
}
var result = JSON.parse(compiler.compile(JSON.stringify(input)))
if (!('contracts' in result) || Object.keys(result['contracts']).length === 0)
{
console.log(filename + ': ERROR')
Expand All @@ -66,7 +76,7 @@ for (var optimize of [false, true])
{
for (var contractName in result['contracts'])
{
console.log(contractName + ' ' + result['contracts'][contractName].bytecode)
console.log(contractName + ' ' + result['contracts'][contractName].evm.bytecode.object)
console.log(contractName + ' ' + result['contracts'][contractName].metadata)
}
}
Expand Down
13 changes: 12 additions & 1 deletion test/externalTests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,16 @@ function test_truffle
cd "$DIR"
echo "Current commit hash: `git rev-parse HEAD`"
npm install
find . -name soljson.js -exec cp "$SOLJSON" {} \;
# Replace solc package by master
for d in node_modules node_modules/truffle/node_modules
do
(
cd $d
rm -rf solc
git clone --depth 1 https://github.com/ethereum/solc-js.git solc
cp "$SOLJSON" solc/
)
done
if [ "$name" == "Zeppelin" -o "$name" == "Gnosis" ]; then
echo "Replaced fixed-version pragmas..."
# Replace fixed-version pragmas in Gnosis (part of Consensys best practice)
Expand All @@ -68,6 +77,8 @@ function test_truffle
rm "$assertsol"
wget https://raw.githubusercontent.com/trufflesuite/truffle-core/ef31bcaa15dbd9bd0f6a0070a5c63f271cde2dbc/lib/testing/Assert.sol -o "$assertsol"
fi
# Change "compileStandard" to "compile"
sed -i s/solc.compileStandard/solc.compile/ "node_modules/truffle/build/cli.bundled.js"
npm run test
)
rm -rf "$DIR"
Expand Down
Loading